Railway Operation Simulator  v2.17.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 #include <windows.h>
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
251  SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 
1108 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1109 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1110  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1111  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1112  {
1113  Utilities->CallLogPop(2566);
1114  return(1);
1115  }
1116  if(GetRouteGraphicPtr(0,1) == EXG)
1117  {
1118  Utilities->CallLogPop(2567);
1119  return(2);
1120  }
1121  if(GetRouteGraphicPtr(1,0) == EXG)
1122  {
1123  Utilities->CallLogPop(2568);
1124  return(3);
1125  }
1126  if(GetRouteGraphicPtr(1,1) == EXG)
1127  {
1128  Utilities->CallLogPop(2569);
1129  return(3);
1130  }
1131  Utilities->CallLogPop(2570);
1132  return(0);
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 // Track functions
1137 // ---------------------------------------------------------------------------
1138 
1139 // ---------------------------------------------------------------------------
1140 
1142 {
1143  TypeOfRoute = 0;
1144  ReducedTimePenalty = false;
1145  BarrierState = Up;
1146  ChangeDuration = 0.0;
1147  BaseElementSpeedTag = 1;
1148  HLoc = 0;
1149  VLoc = 0;
1150  StartTime = TDateTime(0);
1151 }
1152 
1153 // ---------------------------------------------------------------------------
1154 
1156 {
1157 // CurrentSpeedButtonTag = 0; //not assigned yet
1158 
1159  HLocMin = 2000000000;
1160  VLocMin = 2000000000;
1161  HLocMax = -2000000000;
1162  VLocMax = -2000000000;
1163  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1164  CopyFlag = false; // only true for copying, so names aren't copied
1165  AnsiString NL = '\n';
1166 
1167  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1168  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1169  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1170  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1171 
1176 
1177  int InternalLinkCheckArray[9][2] =
1178  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1179 
1180 /* array of valid link values for 'old' location and 'new' location, where
1181  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1182 
1183  for(int x = 0; x < 9; x++)
1184  {
1185  for(int y = 0; y < 2; y++)
1186  {
1187  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1188  }
1189  }
1190 
1191 // Platform and default track element values
1192  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1193 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1194  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1195  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1196  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1197  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1198  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1199  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1200  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1201  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1202 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1203 
1204  int HVArray[10][2] =
1205  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1206 
1207  for(int x = 0; x < 10; x++)
1208  {
1209  for(int y = 0; y < 2; y++)
1210  {
1211  LinkHVArray[x][y] = HVArray[x][y];
1212  }
1213  }
1214  TrackFinished = false;
1215 // DistancesSet = false;
1216 
1217  TSigElement TempSigTable[40] = // original four aspect
1218  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1219  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1220 
1221  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1222  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1223 
1226 
1227  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1228  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1229 
1230  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1231  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1232  {75, 4, RailGraphics->gl75}};
1233 
1234  for(int x = 0; x < 40; x++)
1235  {
1236  SigTable[x] = TempSigTable[x];
1237  }
1238 
1239  TSigElement TempSigTableThreeAspect[40] =
1240  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1241  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1242 
1243  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1244  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1245 
1246  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1247  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1248 
1249  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1250  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1251 
1252  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1253  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1254  {75, 4, RailGraphics->gl75}};
1255 
1256  for(int x = 0; x < 40; x++)
1257  {
1258  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1259  }
1260 
1261  TSigElement TempSigTableTwoAspect[40] =
1262  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1263  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1264 
1265  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1266  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1267 
1268  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1269  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1270 
1271  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1272  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1273 
1274  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1275  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1276  {75, 4, RailGraphics->gl75}};
1277 
1278  for(int x = 0; x < 40; x++)
1279  {
1280  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1281  }
1282 
1283  TSigElement TempSigTableGroundSignal[40] =
1287 
1291 
1295 
1299 
1300  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1303 
1304  for(int x = 0; x < 40; x++)
1305  {
1306  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1307  }
1308 
1309  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1310  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1311  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1312 
1313  for(int x = 0; x < 8; x++)
1314  {
1315  FailedSigTable[x] = TempFailedSigTable[x];
1316  }
1317 
1318  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1319  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1320  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1321 
1322  for(int x = 0; x < 8; x++)
1323  {
1324  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1325  }
1326 
1327 /*
1328  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1329  a single location. These are as follows:-
1330  Directly Adjacent = up, down, left or right - NOT diagonal.
1331  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1332  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1333  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1334 
1335  //t 76
1336  //b 77
1337  //l 78
1338  //r 79
1339  //c 96
1340  //v fb 129
1341  //h fb 130
1342  //v underpass 145
1343  //h underpass 146
1344  //n 131
1345 */
1346 
1347  int Tag76[25][3] =
1348  {{-1, 0, 96}, // c top plat
1349  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1350  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1351  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1352  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1353  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1354  {0, 0, 129}, {0, -1, 145}, // v up
1355  {0, 0, 145}};
1356 
1357  for(int x = 0; x < 25; x++)
1358  {
1359  for(int y = 0; y < 3; y++)
1360  {
1361  Tag76Array[x][y] = Tag76[x][y];
1362  }
1363  }
1364 
1365  int Tag77[25][3] =
1366  {{-1, 0, 96}, // c bot plat
1367  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1368  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1369  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1370  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1371  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1372  {0, 0, 129}, {0, 1, 145}, // v up
1373  {0, 0, 145}};
1374 
1375  for(int x = 0; x < 25; x++)
1376  {
1377  for(int y = 0; y < 3; y++)
1378  {
1379  Tag77Array[x][y] = Tag77[x][y];
1380  }
1381  }
1382 
1383  int Tag78[25][3] =
1384  {{-1, 0, 96}, // c left plat
1385  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1386  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1387  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1388  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1389  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1390  {0, 0, 130}, {-1, 0, 146}, // h up
1391  {0, 0, 146}};
1392 
1393  for(int x = 0; x < 25; x++)
1394  {
1395  for(int y = 0; y < 3; y++)
1396  {
1397  Tag78Array[x][y] = Tag78[x][y];
1398  }
1399  }
1400 
1401  int Tag79[25][3] =
1402  {{-1, 0, 96}, // c right plat
1403  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1404  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1405  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1406  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1407  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1408  {0, 0, 130}, {1, 0, 146}, // h up
1409  {0, 0, 146}};
1410 
1411  for(int x = 0; x < 25; x++)
1412  {
1413  for(int y = 0; y < 3; y++)
1414  {
1415  Tag79Array[x][y] = Tag79[x][y];
1416  }
1417  }
1418 
1419  int Tag96[28][3] =
1420  {{-1, 0, 96}, // c //concourse
1421  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1422  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1423  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1424  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1425  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1426  {0, -1, 129}, {1, 0, 130}, // h fb
1427  {-1, 0, 130}, {0, 1, 145}, // v up
1428  {0, -1, 145}, {1, 0, 146}, // h up
1429  {-1, 0, 146}};
1430 
1431  for(int x = 0; x < 28; x++)
1432  {
1433  for(int y = 0; y < 3; y++)
1434  {
1435  Tag96Array[x][y] = Tag96[x][y];
1436  }
1437  }
1438 
1439  int Tag129[8][3] = // vert fb
1440  {{0, -1, 96}, // c
1441  {0, -1, 77}, // b
1442  {0, -1, 129}, // v fb
1443 
1444  {0, 1, 96}, // c
1445  {0, 1, 76}, // t
1446  {0, 1, 129}, // v fb
1447 
1448  {0, 0, 76}, // t
1449  {0, 0, 77}}; // b
1450 
1451  for(int x = 0; x < 8; x++)
1452  {
1453  for(int y = 0; y < 3; y++)
1454  {
1455  Tag129Array[x][y] = Tag129[x][y];
1456  }
1457  }
1458 
1459  int Tag145[8][3] = // vert up
1460  {{0, -1, 96}, // c
1461  {0, -1, 77}, // b
1462  {0, -1, 145}, // v fb
1463 
1464  {0, 1, 96}, // c
1465  {0, 1, 76}, // t
1466  {0, 1, 145}, // v fb
1467 
1468  {0, 0, 76}, // t
1469  {0, 0, 77}}; // b
1470 
1471  for(int x = 0; x < 8; x++)
1472  {
1473  for(int y = 0; y < 3; y++)
1474  {
1475  Tag145Array[x][y] = Tag145[x][y];
1476  }
1477  }
1478 
1479  int Tag130[8][3] = // hor fb
1480  {{-1, 0, 96}, // c
1481  {-1, 0, 79}, // r
1482  {-1, 0, 130}, // h fb
1483 
1484  {1, 0, 96}, // c
1485  {1, 0, 78}, // l
1486  {1, 0, 130}, // h fb
1487 
1488  {0, 0, 78}, // l
1489  {0, 0, 79}}; // r
1490 
1491  for(int x = 0; x < 8; x++)
1492  {
1493  for(int y = 0; y < 3; y++)
1494  {
1495  Tag130Array[x][y] = Tag130[x][y];
1496  }
1497  }
1498 
1499  int Tag146[8][3] = // hor up
1500  {{-1, 0, 96}, // c
1501  {-1, 0, 79}, // r
1502  {-1, 0, 146}, // h fb
1503 
1504  {1, 0, 96}, // c
1505  {1, 0, 78}, // l
1506  {1, 0, 146}, // h fb
1507 
1508  {0, 0, 78}, // l
1509  {0, 0, 79}}; // r
1510 
1511  for(int x = 0; x < 8; x++)
1512  {
1513  for(int y = 0; y < 3; y++)
1514  {
1515  Tag146Array[x][y] = Tag146[x][y];
1516  }
1517  }
1518 
1519  int Tag131[4][3] =
1520  {{-1, 0, 131}, // n
1521  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1522 
1523  for(int x = 0; x < 4; x++)
1524  {
1525  for(int y = 0; y < 3; y++)
1526  {
1527  Tag131Array[x][y] = Tag131[x][y];
1528  }
1529  }
1530 
1531  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1532  {
1533  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1534  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1535  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1536  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1537  140, 144, 145, 146
1538  };
1539 
1540  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1541  {
1542  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1543  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1544  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1545  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1546  141, 144, 145, 146
1547  };
1548 
1549  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1550  {
1551  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1552  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1553  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1554  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1555  141, 144, 146, 145
1556  };
1557 
1558  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1559  {
1560  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1561  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1562  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1563  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1564  140, 144, 146, 145
1565  };
1566 
1567  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1568  {
1569  FlipArray[x] = InternalFlipArray[x];
1570  MirrorArray[x] = InternalMirrorArray[x];
1571  RotRightArray[x] = InternalRotRightArray[x];
1572  RotLeftArray[x] = InternalRotLeftArray[x];
1573  }
1574 }
1575 
1576 // ---------------------------------------------------------------------------
1578 {
1579 // delete TrackVectorPtr;
1580 // delete FixedTrackArrayPtr;
1581  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1582 
1583  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1584  {
1585  delete UGMIt->second;
1586  UGMIt++;
1587  }
1588  delete GapFlashGreen;
1589  delete GapFlashRed;
1590  // all the rest are cleared by the relevant automatic destructors
1591 }
1592 
1593 // ---------------------------------------------------------------------------
1594 
1596 {
1597  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1598  {
1599 // loc 0 not used, set to bmSolidBgnd
1603 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1623  };
1624 
1625  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1626  {
1627 // loc 0 not used, set to smSolidBgnd
1631 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1650  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1651  };
1652 
1653 // track types
1654  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1655  {
1656  Erase, // 1 0
1657  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1658  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1659  Crossover, Crossover, // 2 15-16
1660  Unused, // 17 (was for text in earlier development) //1 17
1663  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1667  Platform, Platform, Platform, Platform, // 4 76-79
1670  Concourse, // 1 96
1673  Simple, Simple, Simple, Simple, // 4 125-128
1674  FootCrossing, FootCrossing, // 2 129-130
1675  NamedNonStationLocation, // 1 131
1676  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1677  Simple, Simple, Simple, Simple, // 4 140-143
1678  LevelCrossing, // 1 144
1679  FootCrossing, FootCrossing // 2 145 & 146
1680  };
1681 
1682 // links
1683  int Links[FirstUnusedSpeedTagNumber][4] =
1684  {{-1, -1, -1, -1}, // erase element
1685  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1686  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1687 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1688  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1689  {-1, -1, -1, -1}, // unused
1690  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1691  {2, 7, -1, -1}, // simple
1692  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1693 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1694 // (or right diverging if no straight)
1695  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1696  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1697  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1698  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1699  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1700  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1701  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1702  {-1, -1, -1, -1}, // Concourse
1703  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1704  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1705  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1707  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1708  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1709  {-1, -1, -1, -1}, // NamedNonStationLocation
1710  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1711 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1712  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1713  {-1, -1, -1, -1}, // level crossing
1714  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1715  };
1716 
1718  {{NotSet, NotSet, NotSet, NotSet}, // unused
1722  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1724  {NotSet, NotSet, NotSet, NotSet}, // unused
1728  {Connection, Connection, NotSet, NotSet}, // simple
1732  {Lead, Trail, Lead, Trail}, // points
1734  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1742  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1748  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1757  {Connection, Connection, NotSet, NotSet}, // Arrows
1759  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1761  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1763  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1764  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1765  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1766  };
1767 
1768  for(int x = 0; x < 17; x++)
1769  {
1770  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1771  }
1772  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1773 // 17 was the old text value so don't want any graphics (now disused)
1774  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1775  {
1776  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1777  }
1778 }
1779 
1780 // ---------------------------------------------------------------------------
1781 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1782  ExistingGraphicLoaded(false), Width(16), Height(16)
1783 {
1784  OriginalGraphic = new Graphics::TBitmap;
1785  OriginalGraphic->PixelFormat = pf8bit;
1786  OriginalGraphic->Width = Width;
1787  OriginalGraphic->Height = Height;
1788  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1789 }
1790 
1791 // ---------------------------------------------------------------------------
1792 
1793 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1794  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1795 {
1796  OriginalGraphic = new Graphics::TBitmap;
1797  OriginalGraphic->PixelFormat = pf8bit;
1798  OriginalGraphic->Width = Width;
1799  OriginalGraphic->Height = Height;
1800  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1801 }
1802 
1803 // ---------------------------------------------------------------------------
1804 
1806 {
1807  delete OriginalGraphic;
1808 }
1809 
1810 // ---------------------------------------------------------------------------
1811 
1812 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1813 {
1814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1815  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1816  VPos = VPosIn;
1817  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1818 
1819  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1820  SourceRect.init(Left, Top, Left + Width, Top + Height);
1821  ScreenSourceSet = true;
1822  Utilities->CallLogPop(422);
1823 }
1824 
1825 // ---------------------------------------------------------------------------
1826 
1828 {
1829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1830  if(!OverlayLoaded)
1831  {
1832  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1833  }
1834  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1835  {
1836  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1837  }
1838  if(!ScreenSourceSet)
1839  {
1840  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1841  }
1842  if(ExistingGraphicLoaded) // can only call one of the load functions
1843  {
1844  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1845  }
1846  if(OverlayPlotted) // don't load from screen if overlay plotted
1847  {
1848  Utilities->CallLogPop(775);
1849  return;
1850  }
1851  TRect DestRect(0, 0, Width, Height);
1852 
1854  OriginalLoaded = true;
1855  ScreenGraphicLoaded = true;
1856  Utilities->CallLogPop(423);
1857 }
1858 
1859 // ---------------------------------------------------------------------------
1860 
1861 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1862 /*
1863  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1864 */
1865 {
1866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1867  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1868  if(!OverlayLoaded)
1869  {
1870  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1871  }
1872  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1873  {
1874  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1875  }
1876  if(ScreenGraphicLoaded) // can only call one of the load functions
1877  {
1878  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1879  }
1880  Width = WidthIn;
1881  Height = HeightIn;
1882  OriginalGraphic->Width = Width;
1883  OriginalGraphic->Height = Height;
1884  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1885  VPos += VOffset;
1886  TRect DestRect(0, 0, Width, Height);
1887 
1888  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1889  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1890  OriginalLoaded = true;
1891  ExistingGraphicLoaded = true;
1892  Utilities->CallLogPop(424);
1893 }
1894 
1895 // ---------------------------------------------------------------------------
1896 
1897 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1898 {
1899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1900  OverlayGraphic = Overlay;
1901  OverlayLoaded = true;
1902  Utilities->CallLogPop(425);
1903 }
1904 
1905 // ---------------------------------------------------------------------------
1906 
1908 {
1909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1910  if(!OverlayLoaded)
1911  {
1912  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1913  }
1914  if(!OverlayPlotted)
1915  {
1916  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1917  Disp->Update();
1918  OverlayPlotted = true;
1919  }
1920  Utilities->CallLogPop(426);
1921 }
1922 
1923 // ---------------------------------------------------------------------------
1924 
1926 {
1927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1928  if(OverlayPlotted)
1929  {
1930  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1931  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1932  {
1933  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1934  }
1935  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1936  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1937  OverlayPlotted = false;
1938  }
1939  Utilities->CallLogPop(427);
1940 }
1941 
1942 // ---------------------------------------------------------------------------
1943 
1945 {
1946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1947  bool TrackPresent = false;
1948 
1949  if(InactiveTrackVector.size() != 0)
1950  {
1951  Utilities->CallLogPop(1333);
1952  return(false);
1953  }
1954  else if(TrackVector.size() == 0)
1955  {
1956  Utilities->CallLogPop(1334);
1957  return(true);
1958  }
1959  else
1960  {
1961  for(unsigned int x = 0; x < TrackVector.size(); x++)
1962  {
1963  if((TrackElementAt(1042, x).SpeedTag != 0))
1964  {
1965  TrackPresent = true;
1966  }
1967  }
1968  }
1969  Utilities->CallLogPop(1335);
1970  return(!TrackPresent);
1971 }
1972 
1973 // ---------------------------------------------------------------------------
1974 
1975 bool TTrack::NoActiveTrack(int Caller)
1976 {
1977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1978  bool TrackPresent = false;
1979 
1980  if(TrackVector.size() == 0)
1981  {
1982  Utilities->CallLogPop(1582);
1983  return(true);
1984  }
1985  else
1986  {
1987  for(unsigned int x = 0; x < TrackVector.size(); x++)
1988  {
1989  if((TrackElementAt(1043, x).SpeedTag != 0))
1990  {
1991  TrackPresent = true;
1992  }
1993  break;
1994  }
1995  }
1996  Utilities->CallLogPop(1583);
1997  return(!TrackPresent);
1998 }
1999 
2000 // ---------------------------------------------------------------------------
2001 
2002 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2003 {
2004  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2005  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2006  TrackEraseSuccessfulFlag = false;
2007 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2008 // since have to match platforms as well as track
2009 // used to set TrackFinished to false if an element erased
2010 
2011  ErasedTrackVectorPosition = -1; // marker for no element erased
2012  AnsiString SName = "", ErrorString;
2014  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2015  TTrackMapIterator TrackMapPtr;
2016  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2017 
2018  if(TrackVector.size() != 0)
2019  {
2020  TrackMapKeyPair.first = HLocInput;
2021  TrackMapKeyPair.second = VLocInput;
2022  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2023  if(TrackMapPtr != TrackMap.end())
2024  {
2025  bool FoundFlag;
2026  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2027  if(FoundFlag) // should find it as it's in the map
2028  {
2029  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2030  {
2031  SName = TrackElementAt(1, VecPos).LocationName;
2032  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2033  if(ErrorString != "")
2034  {
2035  throw Exception(ErrorString + " for EraseTrackElement 1");
2036  }
2037  LocationNameMultiMap.erase(SNIt);
2038  }
2039  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2040  // ensure erase vector element before map element as iterator no longer valid after a map erase
2041  TrackMap.erase(TrackMapPtr);
2042  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2043  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2045  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2046  if(SName != "")
2047  {
2048  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2049  int HPos, VPos;
2050  if(TextHandler->FindText(1, SName, HPos, VPos))
2051  {
2052  if(TextHandler->TextErase(5, HPos, VPos, SName))
2053  {
2054  ;
2055  } // condition not used
2056 
2057  }
2058  }
2059  ErasedTrackVectorPosition = VecPos;
2060  TrackEraseSuccessfulFlag = true;
2061  }
2062  }
2063  }
2064  if(InactiveTrackVector.size() != 0)
2065  {
2066  unsigned int VecPos;
2067  InactiveTrackMapKeyPair.first = HLocInput;
2068  InactiveTrackMapKeyPair.second = VLocInput;
2069  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2070  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2071  {
2072  SName = "";
2073  VecPos = InactiveTrack2MultiMapIterator->second;
2074  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2075  {
2076  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2077  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2078  if(ErrorString != "")
2079  {
2080  throw Exception(ErrorString + " for EraseTrackElement 2A");
2081  }
2082  LocationNameMultiMap.erase(SNIt);
2083  }
2084  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2085  // ensure erase vector element before map element as iterator no longer valid after a map erase
2086  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2087  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2088  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2090  TrackEraseSuccessfulFlag = true;
2091  if(SName != "")
2092  {
2093  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2094  int HPos, VPos;
2095  if(TextHandler->FindText(2, SName, HPos, VPos))
2096  {
2097  if(TextHandler->TextErase(6, HPos, VPos, SName))
2098  {
2099  ;
2100  } // condition not used
2101 
2102  }
2103  }
2104  }
2105  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2106  {
2107  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2108  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2109  {
2110  SName = "";
2111  VecPos = InactiveTrack2MultiMapIterator->second;
2112  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2113  {
2114  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2115  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2116  if(ErrorString != "")
2117  {
2118  throw Exception(ErrorString + " for EraseTrackElement 2B");
2119  }
2120  LocationNameMultiMap.erase(SNIt);
2121  }
2122  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2123  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2124  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2126  if(SName != "")
2127  {
2128  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2129  int HPos, VPos;
2130  if(TextHandler->FindText(3, SName, HPos, VPos))
2131  {
2132  if(TextHandler->TextErase(7, HPos, VPos, SName))
2133  {
2134  ;
2135  } // condition not used
2136 
2137  }
2138  }
2139  }
2140  }
2141  }
2142  if(TrackEraseSuccessfulFlag)
2143  {
2144  CalcHLocMinEtc(2);
2145  SetTrackFinished(false);
2146  }
2147  if(InternalChecks)
2148  {
2149  CheckMapAndTrack(1); // test
2150  CheckMapAndInactiveTrack(1); // test
2151  CheckLocationNameMultiMap(6); // test
2152  }
2153  Utilities->CallLogPop(428);
2154 }
2155 
2156 // ---------------------------------------------------------------------------
2157 
2158 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2159 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2160 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2161 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2162 {
2163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2164  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2165  bool PlatAllowedFlag = false;
2166 
2167  TrackLinkingRequiredFlag = false;
2168 /*
2169  Not erase, that covered separately.
2170  First check if Current SpeedButton assigned, then check if a platform and only
2171  permit if an appropriate trackpiece already there & not a same platform there.
2172  - can't enter a platform without track first.
2173  Then for non-platforms, check if a track piece already present at location &
2174  reject if so.
2175 */
2176 
2177  TLocationNameMultiMapEntry LocationNameEntry;
2178 
2179  LocationNameEntry.first = "";
2180  if(CurrentTag == 0)
2181  {
2182  Utilities->CallLogPop(429);
2183  return; // not assigned yet
2184  }
2185  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2186 
2187  TempTrackElement.HLoc = HLocInput;
2188  TempTrackElement.VLoc = VLocInput;
2189  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2190 // new at version 0.6 - set signal aspect depending on build mode
2191 
2192  if(TempTrackElement.TrackType == SignalPost)
2193  {
2194  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2195  // pasting a SignalPost can only have values 1 to 4
2196  {
2198  {
2199  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2200  }
2202  {
2203  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2204  }
2206  {
2207  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2208  }
2209  else
2210  {
2211  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2212  }
2213  }
2214  else if(Aspect == 1)
2215  {
2216  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2217  }
2218  else if(Aspect == 2)
2219  {
2220  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2221  }
2222  else if(Aspect == 3)
2223  {
2224  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2225  }
2226  else
2227  {
2228  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2229  }
2230  }
2231  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2232  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2233  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2234  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2235 
2236  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2237  {
2239  {
2240  NonStationOrLevelCrossingPresent = true;
2241  }
2242  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2243  {
2244  NonStationOrLevelCrossingPresent = true;
2245  }
2246  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2247  {
2248  PlatformPresent = true;
2249  }
2250  // no need to check IMPair.second since if that exists it is because .first is a platform
2251  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2252  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2253  }
2254 // check platforms
2255  if(TempTrackElement.TrackType == Platform)
2256  {
2257  if(FoundFlag) // active track element already there
2258  {
2259  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2260  {
2261  ;
2262  }
2263  // same platform type already there so above keeps PlatAllowedFlag false
2264  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2265  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2266  {
2267  PlatAllowedFlag = true;
2268  }
2269  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2270  {
2271  PlatAllowedFlag = true;
2272  }
2273  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2274  {
2275  PlatAllowedFlag = true;
2276  }
2277  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2278  {
2279  PlatAllowedFlag = true;
2280  }
2281  if(PlatAllowedFlag)
2282  {
2283  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2284  TrackPush(1, TempTrackElement);
2285  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2286  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2287  // Must be called AFTER TrackPush
2288  // No need to plot the element - Clearand ... called after this function called
2289  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2290  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2291 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2292 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2293 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2294  if(InternalChecks)
2295  {
2296  CheckMapAndInactiveTrack(5); // test
2297  CheckLocationNameMultiMap(4); // test
2298  }
2299  Utilities->CallLogPop(430);
2300  return;
2301  }
2302  } // if(FoundFlag)
2303 
2304  Utilities->CallLogPop(431);
2305  return;
2306  } // if platform
2307 
2308 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2309  if(TempTrackElement.TrackType == NamedNonStationLocation)
2310  {
2311  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2312  (!FoundFlag && !InactiveFoundFlag))
2313  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2314  {
2315  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2316  TrackPush(2, TempTrackElement);
2317  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2318  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2319  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2320  {
2321 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2322 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2323 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2324  }
2325  if(InternalChecks)
2326  {
2327  CheckMapAndInactiveTrack(11); // test
2328  CheckLocationNameMultiMap(12); // test
2329  }
2330  Utilities->CallLogPop(432);
2331  return;
2332  }
2333  else
2334  {
2335  Utilities->CallLogPop(433);
2336  return;
2337  }
2338  }
2339 // check if a level crossing - OK if placed on a plain straight track
2340  if(TempTrackElement.TrackType == LevelCrossing)
2341  {
2342  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2343  {
2344  TrackPush(11, TempTrackElement);
2345  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2346 // no need for reference to LC element as can't be open
2347  TrackLinkingRequiredFlag = true;
2348  Utilities->CallLogPop(1907);
2349  return;
2350  }
2351  else
2352  {
2353  Utilities->CallLogPop(1906);
2354  return; // was a level crossing but can't place it for some reason
2355  }
2356  }
2357 
2358 // check if another element already there
2359  else if(FoundFlag || InactiveFoundFlag)
2360  {
2361  Utilities->CallLogPop(434);
2362  return; // something already there (active or inactive track)
2363  }
2364 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2365 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2366 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2367 // do this after pushed into vector so that can use EnterLocationName
2368 
2369  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2370  {
2371  TrackPush(3, TempTrackElement);
2372  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2373  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2374  }
2375  else if(TempTrackElement.TrackType == Points)
2376  {
2377  TrackPush(4, TempTrackElement);
2378  bool BothPointFillets = true;
2379  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2380  }
2381  else if(TempTrackElement.TrackType == SignalPost)
2382  {
2383  TrackPush(10, TempTrackElement);
2384  PlotSignal(12, TempTrackElement, Display);
2385  }
2386  else
2387  {
2388  TrackPush(5, TempTrackElement);
2389  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2390  }
2391  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2392  {
2393  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2394  }
2395  if(InternalChecks)
2396  {
2397  CheckMapAndTrack(2); // test
2398  CheckMapAndInactiveTrack(2); // test
2399  CheckLocationNameMultiMap(5); // test
2400  }
2401  Utilities->CallLogPop(2062);
2402 }
2403 
2404 // ---------------------------------------------------------------------------
2405 
2406 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2407  bool InternalChecks)
2408 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2409 {
2410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2411  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2412  bool PlatAllowedFlag = false;
2413 
2414  TrackLinkingRequiredFlag = false;
2415  TLocationNameMultiMapEntry LocationNameEntry;
2416 
2417  LocationNameEntry.first = "";
2418  if(TempTrackElement.SpeedTag == 0)
2419  {
2420  Utilities->CallLogPop(2063);
2421  return; // not assigned yet
2422  }
2423  TempTrackElement.HLoc = HLocInput;
2424  TempTrackElement.VLoc = VLocInput;
2425  for(int x = 0; x < 4; x++) // unset any gaps
2426  {
2427  if(TempTrackElement.Config[x] == Gap)
2428  {
2429  TempTrackElement.ConnLinkPos[x] = -1;
2430  }
2431  TempTrackElement.Conn[x] = -1;
2432  }
2433  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2434 // new at version 0.6 - set signal aspect depending on build mode
2435  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2436  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2437 
2438  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2439  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2440  // for the active track element because these aren't set
2441  // if don't do this then get a mismatch error during map checks later
2442 
2443  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2444 
2445  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2446  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2447 
2448  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2449  {
2450  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2451  {
2452  NonStationOrLevelCrossingPresent = true;
2453  }
2454  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2455  {
2456  NonStationOrLevelCrossingPresent = true;
2457  }
2458  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2459  {
2460  PlatformPresent = true;
2461  }
2462  // no need to check IMPair.second since if that exists it is because .first is a platform
2463  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2464  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2465  }
2466 // check platforms
2467  if(TempTrackElement.TrackType == Platform)
2468  {
2469  if(FoundFlag) // active track element already there
2470  {
2471  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2472  {
2473  ;
2474  }
2475  // same platform type already there so above keeps PlatAllowedFlag false
2476  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2477  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2478  {
2479  PlatAllowedFlag = true;
2480  }
2481  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2482  {
2483  PlatAllowedFlag = true;
2484  }
2485  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2486  {
2487  PlatAllowedFlag = true;
2488  }
2489  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2490  {
2491  PlatAllowedFlag = true;
2492  }
2493  if(PlatAllowedFlag)
2494  {
2495  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2496  TrackPush(12, TempTrackElement);
2497 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2498  {
2499  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2500  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2501  }
2502  // Must be called AFTER TrackPush
2503 // No need to plot the element - Clearand ... called after this function called
2504  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2505  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2506 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2507 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2508 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2509  if(InternalChecks)
2510  {
2511  CheckMapAndInactiveTrack(12); // test
2512  CheckLocationNameMultiMap(20); // test
2513  }
2514  Utilities->CallLogPop(2064);
2515  return;
2516  }
2517  } // if(FoundFlag)
2518 
2519  Utilities->CallLogPop(2065);
2520  return;
2521  } // if platform
2522 
2523 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2524  if(TempTrackElement.TrackType == NamedNonStationLocation)
2525  {
2526  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2527  (!FoundFlag && !InactiveFoundFlag))
2528  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2529  {
2530  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2531  TrackPush(13, TempTrackElement);
2532 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2533  {
2534  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2535  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2536  }
2537  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2538  {
2539 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2540 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2541 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2542  }
2543  if(InternalChecks)
2544  {
2545  CheckMapAndInactiveTrack(13); // test
2546  CheckLocationNameMultiMap(21); // test
2547  }
2548  Utilities->CallLogPop(2066);
2549  return;
2550  }
2551  else
2552  {
2553  Utilities->CallLogPop(2067);
2554  return;
2555  }
2556  }
2557 // check if a level crossing - OK if placed on a plain straight track
2558  if(TempTrackElement.TrackType == LevelCrossing)
2559  {
2560  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2561  {
2562  TrackPush(14, TempTrackElement);
2563  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2564 // no need for reference to LC element as can't be open
2565  TrackLinkingRequiredFlag = true;
2566  Utilities->CallLogPop(2068);
2567  return;
2568  }
2569  else
2570  {
2571  Utilities->CallLogPop(2069);
2572  return; // was a level crossing but can't place it for some reason
2573  }
2574  }
2575 
2576 // check if another element already there
2577  else if(FoundFlag || InactiveFoundFlag)
2578  {
2579  Utilities->CallLogPop(2070);
2580  return; // something already there (active or inactive track)
2581  }
2582 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2583 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2584 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2585 // do this after pushed into vector so that can use EnterLocationName
2586 
2587  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2588  {
2589  TrackPush(15, TempTrackElement);
2590  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2591  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2592  }
2593  else if(TempTrackElement.TrackType == Points)
2594  {
2595  TrackPush(16, TempTrackElement);
2596  bool BothPointFillets = true;
2597  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2598  }
2599  else if(TempTrackElement.TrackType == SignalPost)
2600  {
2601  TrackPush(17, TempTrackElement);
2602  PlotSignal(14, TempTrackElement, Display);
2603  }
2604  else
2605  {
2606  TrackPush(18, TempTrackElement);
2607  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2608  }
2609  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2610  {
2611  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2612  }
2613  if(InternalChecks)
2614  {
2615  CheckMapAndTrack(12); // test
2616  CheckMapAndInactiveTrack(14); // test
2617  CheckLocationNameMultiMap(22); // test
2618  }
2619  Utilities->CallLogPop(2071);
2620 }
2621 
2622 // ---------------------------------------------------------------------------
2623 
2624 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2625 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2626 // return bool = true for success
2627 // LocError = true for location error & HLoc & VLoc to be inverted
2628 {
2629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2630  LocError = false;
2631  SetTrackFinished(false);
2632  if(TrackVector.size() == 0)
2633  {
2634  Utilities->CallLogPop(437);
2635  return(false);
2636  }
2637  if(GapsUnset(7))
2638  {
2639  if(GiveMessages)
2640  {
2641  ShowMessage("Gaps must be set before track can be validated");
2642  }
2643  Utilities->CallLogPop(1135);
2644  return(false);
2645  }
2646 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2647 // returns true for any unset gaps
2649  {
2650  // can keep this exception as protected by the GapsUnset call above
2651  throw Exception("Error, gaps unset when TryToConnectTrack called");
2652  }
2654  CheckGapMap(1); // test
2655 // Gap connections now securely defined
2656 
2657  CheckMapAndTrack(8); // test
2658 
2659 // Perform a pre-check prior to TrackMap being compiled
2660  if(GiveMessages)
2661  {
2662  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2663  {
2664  Utilities->CallLogPop(439);
2665  return(false);
2666  }
2667  }
2668  else
2669  {
2670  if(!LinkTrackNoMessages(1, false))
2671  {
2672  Utilities->CallLogPop(1131);
2673  return(false);
2674  }
2675  }
2676 // here if pre-check successful
2677  if(!RepositionAndMapTrack(0))
2678  {
2679  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2680  Utilities->CallLogPop(1138);
2681  return(false);
2682  }
2683 // now perform the final assembly - FinalCall = true
2684  if(GiveMessages)
2685  {
2686  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2687  {
2688  Utilities->CallLogPop(1116);
2689  return(false);
2690  }
2691  }
2692  else
2693  {
2694  if(!LinkTrackNoMessages(2, true))
2695  {
2696  Utilities->CallLogPop(1132);
2697  return(false);
2698  }
2699  }
2700 // success
2701 
2702  PopulateLCVector(0);
2703  CheckGapMap(2); // test
2704  CheckMapAndTrack(3); // test
2705  CheckMapAndInactiveTrack(3); // test
2706  CheckLocationNameMultiMap(9); // test
2707  SetTrackFinished(true);
2708 
2709 // Build ContinuationNameMap
2710  std::pair<AnsiString, char>TempMapPair;
2711 
2712  ContinuationNameMap.clear();
2713  for(int x = 0; x < Track->TrackVectorSize(); x++)
2714  {
2715  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2716  {
2717  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2718  TempMapPair.second = 'x'; // unused
2719  ContinuationNameMap.insert(TempMapPair);
2720  }
2721  }
2722 
2723 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2724 //(don't report blue areas without track as these unlikely to be mistakes)
2725 
2726  if(TrackFinished)
2727  {
2728  AnsiString Name = "";
2729  typedef std::list<AnsiString> TNoPlatsList;
2730  TNoPlatsList::iterator NPLIt;
2731  TNoPlatsList NoPlatsList;
2732  typedef std::list<AnsiString> TLocNameList;
2733  TLocNameList LocNameList; //single entry for each name
2736  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2737  {
2738  LocNameList.push_back(LNMMIt->first);
2739  }
2740  LocNameList.sort();
2741  LocNameList.unique();
2742  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2743  {
2744  Name = *LNLIt;
2745  MMRange = LocationNameMultiMap.equal_range(Name);
2746  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2747  {
2748  continue;
2749  }
2750  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2751  {
2752  if((LNMMIt->second) < 0) //active track element
2753  {
2754  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2755  {
2756  break;
2757  }
2758  }
2759  else //inactive
2760  {
2761  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2762  {
2763  break;
2764  }
2765  }
2766  TempIt = MMRange.second;
2767  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2768  {
2769  NoPlatsList.push_back(Name);
2770  }
2771  }
2772  }
2773  if(!NoPlatsList.empty())
2774  {
2775  AnsiString NoPlatsAnsiList = "";
2776  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2777  {
2778  NoPlatsAnsiList += *NPLIt + '\n';
2779  }
2780  if(!NoPlatsMessageSent)
2781  {
2782  if(NoPlatsList.size() > 1)
2783  {
2784  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2785  }
2786  else
2787  {
2788  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2789  }
2790  NoPlatsMessageSent = true;
2791  }
2792  }
2793  }
2794  Utilities->CallLogPop(440);
2795  return(true);
2796 }
2797 
2798 // ---------------------------------------------------------------------------
2799 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2800 // unused - too time-consuming - double brute force search
2801 {
2802  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2803  int NewHLoc, NewVLoc;
2804  bool ConnectionFoundFlag, LinkFoundFlag;
2805 
2806  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2807  {
2808  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2809  {
2810  if(TrackElementAt(1061, x).Link[y] <= 0)
2811  {
2812  continue; // no link
2813  }
2814  if(TrackElementAt(1062, x).Config[y] == End)
2815  {
2816  continue; // buffer or continuation
2817  }
2818  if(TrackElementAt(1063, x).Config[y] == Gap)
2819  {
2820  continue; // gap jump
2821  }
2822  // get required H & V for track element joining link 'y'
2823  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2824  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2825  // find track element if present
2826  ConnectionFoundFlag = false;
2827  for(unsigned int z = 0; z < TrackVector.size(); z++)
2828  {
2829 // if(TrackElementAt(5, z).TrackType == Platform)
2830 // continue; //skip platforms
2831  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2832  {
2833  ConnectionFoundFlag = true;
2834  // find connecting link in the newly found track element if there is one
2835  LinkFoundFlag = false;
2836  for(unsigned int a = 0; a < 4; a++)
2837  {
2838  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2839  {
2840  LinkFoundFlag = true;
2841  }
2842  }
2843  // if there isn't a corresponding link set the invert values for the offending element
2844  if(!LinkFoundFlag)
2845  {
2846  HLoc = TrackElementAt(1072, x).HLoc;
2847  VLoc = TrackElementAt(1073, x).VLoc;
2848  Utilities->CallLogPop(441);
2849  return(true);
2850  }
2851  break; // success, so break out of 'z' loop
2852  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2853 
2854  } // for z...
2855  // if there isn't a connection set the invert values for the offending element
2856  if(!ConnectionFoundFlag)
2857  {
2858  HLoc = TrackElementAt(1074, x).HLoc;
2859  VLoc = TrackElementAt(1075, x).VLoc;
2860  Utilities->CallLogPop(442);
2861  return(true);
2862  }
2863  } // for y....
2864  } // for x...
2865  Utilities->CallLogPop(443);
2866  return(false); // all OK
2867 }
2868 
2869 // ---------------------------------------------------------------------------
2870 
2871 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2872 {
2873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2874  TrackElement.LogTrack(0));
2875  bool FoundFlag;
2876 
2877  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2878  if(FoundFlag)
2879  {
2880  TrackElement = TrackElementAt(1076, Position);
2881  }
2882  Utilities->CallLogPop(444);
2883  return(FoundFlag);
2884 }
2885 
2886 // ---------------------------------------------------------------------------
2887 
2889 {
2890  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2891  if(NextTrackElementPtr >= TrackVector.end())
2892  {
2893  Utilities->CallLogPop(1336);
2894  return(false);
2895  }
2896  Next = *NextTrackElementPtr;
2898  Utilities->CallLogPop(1337);
2899  return(true);
2900 }
2901 
2902 // ---------------------------------------------------------------------------
2903 
2905 {
2906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2908  {
2909  Utilities->CallLogPop(1338);
2910  return(false);
2911  }
2912  Next = *NextTrackElementPtr;
2914  Utilities->CallLogPop(1339);
2915  return(true);
2916 }
2917 
2918 // ---------------------------------------------------------------------------
2919 
2920 int TTrack::NumberOfGaps(int Caller)
2921 
2922 {
2923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2924  int Count = 0;
2925 
2926  if(TrackVector.size() == 0)
2927  {
2928  Utilities->CallLogPop(1340);
2929  return(0);
2930  }
2931  for(unsigned int x = 0; x < TrackVector.size(); x++)
2932  {
2933  if(TrackElementAt(1077, x).TrackType == GapJump)
2934  {
2935  Count++;
2936  }
2937  }
2938  Utilities->CallLogPop(1341);
2939  return(Count);
2940 }
2941 
2942 // ---------------------------------------------------------------------------
2944 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2945 // returns true for any unset gaps
2946 {
2947  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2948  bool UnsetGaps = false;
2949 
2950  if(TrackVector.size() == 0)
2951  {
2952  Utilities->CallLogPop(445);
2953  return(false);
2954  }
2955  for(unsigned int x = 0; x < TrackVector.size(); x++)
2956  {
2957  if(TrackElementAt(1078, x).TrackType != GapJump)
2958  {
2959  for(unsigned int y = 0; y < 4; y++)
2960  {
2961  TrackElementAt(1079, x).Conn[y] = -1;
2962  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2963  }
2964  }
2965  else // GapJump
2966  {
2967 // int tempint = TrackElementAt(, x).Conn[0);
2968 
2969  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2970  {
2971  for(unsigned int y = 0; y < 4; y++)
2972  {
2973  TrackElementAt(1082, x).Conn[y] = -1;
2974  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2975  }
2976  UnsetGaps = true;
2977  continue; // to next 'x'
2978  }
2979  else // set, but may not have matching element, or that element may not be set
2980  {
2981  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2982  {
2983  TrackElementAt(1084, x).Conn[y] = -1;
2984  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2985  }
2986 
2987  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2988  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2989  {
2990  for(unsigned int y = 0; y < 4; y++)
2991  {
2992  TrackElementAt(1087, x).Conn[y] = -1;
2993  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2994  }
2995  UnsetGaps = true;
2996  continue; // to next 'x'
2997  }
2998 // here if gap connection is itself a GapJump
2999  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3000  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3001  // if not clear Conns & CLks & reset Lk[0]
3002  {
3003  for(unsigned int y = 0; y < 4; y++)
3004  {
3005  TrackElementAt(1090, x).Conn[y] = -1;
3006  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3007  }
3008  UnsetGaps = true;
3009  continue; // to next 'x'
3010  }
3011 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3012 // hence no more action needed on these Conns & CLks
3013  }
3014  } // else //gap jump
3015 
3016  } // for x...
3017  Utilities->CallLogPop(446);
3018  return(UnsetGaps);
3019 }
3020 
3021 // ---------------------------------------------------------------------------
3022 
3023 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3024 {
3025 // VecFile already open and its pointer at right place on calling
3026  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3027  int TempInt;
3028 
3029  TrackClear(1);
3030 // load track elements
3031  int NumberOfActiveElements = 0;
3032 
3033  GraphicsFollow = false;
3034  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3035  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3036 
3037  if(MarkerString[MarkerString.Length()] == '1')
3038  {
3039  GraphicsFollow = true;
3040  }
3041  for(int x = 0; x < NumberOfActiveElements; x++)
3042  {
3043  VecFile >> TempInt; // TrackVectorNumber, not used
3044  VecFile >> TempInt; // SpeedTag
3045  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3046  VecFile >> TempInt;
3047  TrackElement.HLoc = TempInt;
3048  VecFile >> TempInt;
3049  TrackElement.VLoc = TempInt;
3050  if(TrackElement.TrackType == GapJump)
3051  {
3052  VecFile >> TempInt;
3053  TrackElement.ConnLinkPos[0] = TempInt;
3054  VecFile >> TempInt;
3055  TrackElement.Conn[0] = TempInt;
3056  }
3057  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3058  {
3059  VecFile >> TempInt;
3060  TrackElement.Attribute = TempInt;
3061  }
3062  if(TrackElement.TrackType == SignalPost)
3063  {
3064  VecFile >> TempInt;
3065  if(TempInt == 0)
3066  {
3067  TrackElement.CallingOnSet = false;
3068  }
3069  else
3070  {
3071  TrackElement.CallingOnSet = true;
3072  }
3073  }
3074  VecFile >> TempInt;
3075  TrackElement.Length01 = TempInt;
3076  VecFile >> TempInt;
3077  TrackElement.Length23 = TempInt;
3078  VecFile >> TempInt;
3079  if((TempInt != -1) && (TempInt < 10))
3080  {
3081  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3082  }
3083  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3084  {
3085  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3086  }
3087  TrackElement.SpeedLimit01 = TempInt;
3088  VecFile >> TempInt;
3089  if((TempInt != -1) && (TempInt < 10))
3090  {
3091  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3092  }
3093  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3094  {
3095  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3096  }
3097  TrackElement.SpeedLimit23 = TempInt;
3098 
3099  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3100  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3101  SetElementID(0, TrackElement);
3102  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3103 // new for v0.6
3104  if(TrackElement.TrackType == SignalPost)
3105  {
3106  if(Marker[1] == '3')
3107  {
3108  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3109  }
3110  else if(Marker[1] == '2')
3111  {
3112  TrackElement.SigAspect = TTrackElement::TwoAspect;
3113  }
3114  else if(Marker[1] == 'G')
3115  {
3116  TrackElement.SigAspect = TTrackElement::GroundSignal;
3117  }
3118  else
3119  {
3120  TrackElement.SigAspect = TTrackElement::FourAspect;
3121  }
3122  }
3123  if(TrackElement.SpeedTag != 0)
3124  {
3125  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3126  }
3127  }
3128  int NumberOfInactiveElements = 0;
3129 
3130  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3131  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3132  for(int x = 0; x < NumberOfInactiveElements; x++)
3133  {
3134  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3135  VecFile >> TempInt; // SpeedTag
3136  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3137  VecFile >> TempInt;
3138  TrackElement.HLoc = TempInt;
3139  VecFile >> TempInt;
3140  TrackElement.VLoc = TempInt;
3141  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3142  SetElementID(3, TrackElement);
3143  TrackPush(9, TrackElement);
3144  Utilities->LoadFileString(VecFile); // marker
3145  }
3146  bool LocError = false; // needed for TryToConnectTrack but not used
3147  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3148 
3149  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3150  {
3151  SetTrackFinished(true);
3152  }
3153  else
3154  {
3155  SetTrackFinished(false);
3156  }
3157 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3158 // CheckMapAndInactiveTrack(8);
3159 // CheckLocationNameMultiMap(10);
3160  Utilities->CallLogPop(448);
3161 }
3162 
3163 // ---------------------------------------------------------------------------
3164 
3165 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3166 {
3167 // VecFile already open and its pointer at right place on calling
3168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3169 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3170 // & load into UserGraphicItem then store in UserGraphicVector
3171  UserGraphicVector.clear();
3172  TUserGraphicItem UGI;
3173  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3174 
3175  for(int x = 0; x < NumberOfGraphics; x++)
3176  {
3177  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3178  UGI.HPos = Utilities->LoadFileInt(VecFile);
3179  UGI.VPos = Utilities->LoadFileInt(VecFile);
3180  UGI.Width = 0; // provisional value
3181  UGI.Height = 0; // provisional value
3182  UGI.UserGraphic = NULL; // provisional value
3183  UserGraphicVector.push_back(UGI);
3184  }
3185 // now load the map & set Width, Height & TPicture*
3186  bool FileError = false;
3187 
3188  for(int x = 0; x < NumberOfGraphics; x++)
3189  {
3190  if(FileError)
3191  {
3192  break; // otherwise keeps going round the loop
3193  }
3194  UGI = UserGraphicVectorAt(0, x);
3195  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3196  {
3197  try
3198  {
3199 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3200  UGME.first = UGI.FileName;
3201  UGME.second = new TPicture;
3202  UGME.second->LoadFromFile(UGME.first); // errors caught below
3203  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3204  {
3205  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3206  }
3207  UGI.UserGraphic = UGME.second;
3208  UGI.Width = UGI.UserGraphic->Width;
3209  UGI.Height = UGI.UserGraphic->Height;
3210  UserGraphicVectorAt(1, x) = UGI;
3211  }
3212  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3213  {
3214  //message already sent in CheckUserGraphics
3215  FileError = true;
3216  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3217  if(!UserGraphicMap.empty())
3218  {
3219  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3220  {
3221  delete UGMIt->second;
3222  }
3223  UserGraphicMap.clear();
3224  }
3225  }
3226  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  }
3241  else
3242  {
3243  bool FoundInMap = false;
3244  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3245  {
3246  if(UGI.FileName == UGMIt->first) // already exists in map
3247  {
3248  UGI.UserGraphic = UGMIt->second;
3249  UGI.Width = UGI.UserGraphic->Width;
3250  UGI.Height = UGI.UserGraphic->Height;
3251  UserGraphicVectorAt(2, x) = UGI;
3252  FoundInMap = true;
3253  break;
3254  }
3255  }
3256  if(!FoundInMap)
3257  {
3258  try
3259  {
3261  UGME.first = UGI.FileName;
3262  UGME.second = new TPicture;
3263  UGME.second->LoadFromFile(UGME.first); // errors caught below
3264  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3265  {
3266  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3267  }
3268  UGI.UserGraphic = UGME.second;
3269  UGI.Width = UGI.UserGraphic->Width;
3270  UGI.Height = UGI.UserGraphic->Height;
3271  UserGraphicVectorAt(3, x) = UGI;
3272  }
3273  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3274  {
3275  //message already sent in CheckUserGraphics
3276  FileError = true;
3277  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3278  if(!UserGraphicMap.empty())
3279  {
3280  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3281  {
3282  delete UGMIt->second;
3283  }
3284  UserGraphicMap.clear();
3285  }
3286  }
3287  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3288  {
3289  //message already sent in CheckUserGraphics
3290  FileError = true;
3291  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3292  if(!UserGraphicMap.empty())
3293  {
3294  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3295  {
3296  delete UGMIt->second;
3297  }
3298  UserGraphicMap.clear();
3299  }
3300  }
3301  }
3302  }
3303  }
3304  Utilities->CallLogPop(2167);
3305 }
3306 
3307 // ---------------------------------------------------------------------------
3308 
3309 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3310 {
3311 // VecFile already open and its pointer at right place on calling
3312 // if GraphicsFollow true, then save Marker as **Active elements**1
3313 // save trackfinished flag
3314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3315  TTrackElement TrackElement, InactiveTrackElement;
3316 
3317 // save track elements
3318  Utilities->SaveFileInt(VecFile, TrackVector.size());
3319  if(GraphicsFollow)
3320  {
3321  VecFile << "**Active elements**1" << '\0' << '\n';
3322  }
3323  else
3324  {
3325  VecFile << "**Active elements**" << '\0' << '\n';
3326  }
3327  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3328  {
3329  TrackElement = TrackElementAt(1092, x);
3330  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3331  VecFile << TrackElement.SpeedTag << '\n';
3332  VecFile << TrackElement.HLoc << '\n';
3333  VecFile << TrackElement.VLoc << '\n';
3334  if(TrackElement.TrackType == GapJump)
3335  {
3336  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3337  VecFile << TrackElement.Conn[0] << '\n';
3338  }
3339  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3340  {
3341  VecFile << TrackElement.Attribute << '\n';
3342  }
3343  if(TrackElement.TrackType == SignalPost)
3344  {
3345  if(TrackElement.CallingOnSet)
3346  {
3347  VecFile << int(1) << '\n';
3348  }
3349  else
3350  {
3351  VecFile << int(0) << '\n';
3352  }
3353  }
3354  VecFile << TrackElement.Length01 << '\n';
3355  VecFile << TrackElement.Length23 << '\n';
3356  VecFile << TrackElement.SpeedLimit01 << '\n';
3357  VecFile << TrackElement.SpeedLimit23 << '\n';
3358  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3359  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3360 // new for v0.6
3361  if(TrackElement.TrackType == SignalPost)
3362  {
3363  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3364  {
3365  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3366  }
3367  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3368  {
3369  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3370  }
3371  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3372  {
3373  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374  }
3375  else // 4 aspect
3376  {
3377  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3378  }
3379  }
3380  else
3381  {
3382  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3383  }
3384  }
3385 
3386  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3387  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3388  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3389  {
3390  InactiveTrackElement = InactiveTrackElementAt(136, x);
3391  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3392  VecFile << InactiveTrackElement.SpeedTag << '\n';
3393  VecFile << InactiveTrackElement.HLoc << '\n';
3394  VecFile << InactiveTrackElement.VLoc << '\n';
3395  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3396  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3397  }
3398  Utilities->CallLogPop(449);
3399 }
3400 
3401 // ---------------------------------------------------------------------------
3402 
3403 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3404 {
3405 // VecFile already open and its pointer at right place on calling
3406 // check trackfinished flag
3407 // inactive elements follow immediately after active elements, no need to check for a marker between them
3408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3409  int TempInt;
3410 
3411  GraphicsFollow = false;
3412  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3413  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3414  {
3415  Utilities->CallLogPop(1513);
3416  return(false);
3417  }
3418 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3419  AnsiString MarkerString;
3420 
3421  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3422  {
3423  Utilities->CallLogPop(1758);
3424  return(false);
3425  }
3426  if(MarkerString[MarkerString.Length()] == '1')
3427  {
3428  GraphicsFollow = true;
3429  }
3430  for(int x = 0; x < NumberOfActiveElements; x++)
3431  {
3432  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3433  {
3434  Utilities->CallLogPop(1759);
3435  return(false);
3436  }
3437  VecFile >> TempInt;
3438  int SpeedTag = TempInt;
3439  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3440  {
3441  Utilities->CallLogPop(1514);
3442  return(false);
3443  }
3444  VecFile >> TempInt;
3445  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3446  {
3447  Utilities->CallLogPop(1495);
3448  return(false);
3449  }
3450  VecFile >> TempInt;
3451  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3452  {
3453  Utilities->CallLogPop(1497);
3454  return(false);
3455  }
3456  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3457  {
3458  VecFile >> TempInt;
3459  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3460  {
3461  Utilities->CallLogPop(1499);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3466  {
3467  Utilities->CallLogPop(1500);
3468  return(false);
3469  }
3470  }
3471  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3472  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3473  {
3474  VecFile >> TempInt;
3475  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3476  {
3477  Utilities->CallLogPop(1502);
3478  return(false);
3479  }
3480  }
3481  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3482  {
3483  VecFile >> TempInt;
3484  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3485  {
3486  Utilities->CallLogPop(1155);
3487  return(false);
3488  }
3489  }
3490  VecFile >> TempInt;
3491  if((TempInt < -1) || (TempInt > 999999)) // Length01
3492  {
3493  Utilities->CallLogPop(1503);
3494  return(false);
3495  }
3496  VecFile >> TempInt;
3497  if((TempInt < -1) || (TempInt > 999999)) // Length23
3498  {
3499  Utilities->CallLogPop(1504);
3500  return(false);
3501  }
3502  VecFile >> TempInt;
3503  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3504  {
3505  Utilities->CallLogPop(1505);
3506  return(false);
3507  }
3508  VecFile >> TempInt;
3509  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3510  {
3511  Utilities->CallLogPop(1506);
3512  return(false);
3513  }
3514  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3515  {
3516  Utilities->CallLogPop(1142);
3517  return(false); // LocationName
3518  }
3519  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3520  {
3521  Utilities->CallLogPop(1143);
3522  return(false); // ActiveTrackElementName
3523  }
3524  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3525  {
3526  Utilities->CallLogPop(1787);
3527  return(false); // marker
3528  }
3529  }
3530  int NumberOfInactiveElements = 0;
3531 
3532  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3533  if(NumberOfInactiveElements < 0) // No of active elements
3534  {
3535  Utilities->CallLogPop(1493);
3536  return(false);
3537  }
3538  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3539  {
3540  Utilities->CallLogPop(1764);
3541  return(false); // **Inactive elements** marker
3542  }
3543  for(int x = 0; x < NumberOfInactiveElements; x++)
3544  {
3545  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3546  {
3547  Utilities->CallLogPop(1765);
3548  return(false);
3549  }
3550  VecFile >> TempInt;
3551  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3552  {
3553  Utilities->CallLogPop(1494);
3554  return(false);
3555  }
3556  VecFile >> TempInt;
3557  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3558  {
3559  Utilities->CallLogPop(1496);
3560  return(false);
3561  }
3562  VecFile >> TempInt;
3563  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3564  {
3565  Utilities->CallLogPop(1498);
3566  return(false);
3567  }
3568  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3569  {
3570  Utilities->CallLogPop(1144);
3571  return(false); // LocationName
3572  }
3573  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3574  {
3575  Utilities->CallLogPop(1788);
3576  return(false); // marker
3577  }
3578  }
3579  Utilities->CallLogPop(1507);
3580  return(true);
3581 }
3582 
3583 // ---------------------------------------------------------------------------
3584 
3585 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3586 {
3587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3588  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3589 
3590  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3591  {
3592  Utilities->CallLogPop(2168);
3593  return(false);
3594  }
3595  // filename in Graphics folder, then HPos, then VPos
3596  AnsiString FileName = "", TempStr = "";
3597 
3598  for(int x = 0; x < NumberOfGraphics; x++)
3599  {
3600  TPicture *TempPicture = new TPicture;
3601  try
3602  {
3603  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3604  {
3605  Utilities->CallLogPop(2169);
3606  delete TempPicture;
3607  return(false);
3608  }
3609  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3610  delete TempPicture;
3611  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3612  {
3613  Utilities->CallLogPop(2170);
3614  return(false);
3615  }
3616  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3617  {
3618  Utilities->CallLogPop(2171);
3619  return(false);
3620  }
3621  }
3622  catch(const EInvalidGraphic &e) //non error catch
3623  {
3624  //move file pointer to end of graphic section for later checks in session files
3625  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3626  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3627  for(int y = x + 1; y < NumberOfGraphics; y++)
3628  {
3629  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3630  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3631  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3632  }
3633  ShowMessage(FileName +
3634  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3635  Utilities->CallLogPop(2172);
3636  delete TempPicture;
3637  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3638  }
3639  catch(const Exception &e) //non error catch
3640  {
3641  //move file pointer to end of graphic section for later checks in session files
3642  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3643  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3644  for(int y = x + 1; y < NumberOfGraphics; y++)
3645  {
3646  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3647  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3648  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3649  }
3650  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3651  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3652  Utilities->CallLogPop(2173);
3653  delete TempPicture;
3654  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3655  }
3656  }
3657  Utilities->CallLogPop(2174);
3658  return(true);
3659 }
3660 
3661 // ---------------------------------------------------------------------------
3662 
3663 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3664 {
3665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3666  int VecSize = Track->BarriersDownVector.size();
3667 
3668  Utilities->SaveFileInt(OutFile, VecSize);
3669  for(int x = 0; x < VecSize; x++)
3670  {
3672  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3673  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3674  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3675  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3676  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3677  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3678  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3679  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3680  }
3681  Utilities->CallLogPop(1963);
3682 }
3683 
3684 // ---------------------------------------------------------------------------
3685 
3686 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3687 {
3688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3689  int VecSize = Track->ChangingLCVector.size();
3690 
3691  Utilities->SaveFileInt(OutFile, VecSize);
3692  for(int x = 0; x < VecSize; x++)
3693  {
3695  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3696  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3697  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3698  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3699  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3700  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3701  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3702  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3703  }
3704  Utilities->CallLogPop(1980);
3705 }
3706 
3707 // ---------------------------------------------------------------------------
3708 
3709 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3710 {
3711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3712  int VecSize = Utilities->LoadFileInt(VecFile);
3713 
3714  for(int x = 0; x < VecSize; x++)
3715  {
3716  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3717  {
3718  Utilities->CallLogPop(1970);
3719  return(false);
3720  }
3721  if(!Utilities->CheckFileBool(VecFile))
3722  {
3723  Utilities->CallLogPop(1971);
3724  return(false);
3725  }
3726  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3727  {
3728  Utilities->CallLogPop(1972);
3729  return(false);
3730  }
3731  if(!Utilities->CheckFileDouble(VecFile))
3732  {
3733  Utilities->CallLogPop(1973);
3734  return(false);
3735  }
3736  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3737  {
3738  Utilities->CallLogPop(1974);
3739  return(false);
3740  }
3741  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3742  {
3743  Utilities->CallLogPop(1975);
3744  return(false);
3745  }
3746  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3747  {
3748  Utilities->CallLogPop(1976);
3749  return(false);
3750  }
3751  if(!Utilities->CheckFileDouble(VecFile))
3752  {
3753  Utilities->CallLogPop(1977);
3754  return(false);
3755  }
3756  }
3757  Utilities->CallLogPop(1978);
3758  return(true);
3759 }
3760 
3761 // ---------------------------------------------------------------------------
3762 
3763 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3764 {
3765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3766  int VecSize = Utilities->LoadFileInt(VecFile);
3767 
3768  for(int x = 0; x < VecSize; x++)
3769  {
3770  TActiveLevelCrossing TALC;
3771  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3772  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3773  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3774  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3775  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3776  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3777  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3778  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3779  BarriersDownVector.push_back(TALC);
3780  }
3781  Utilities->CallLogPop(1979);
3782 }
3783 
3784 // ---------------------------------------------------------------------------
3785 
3786 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3787 /*
3788  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3789  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3790  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3791 */
3792 {
3793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3794  TTrackElement Next;
3795 
3796 // Disp->ClearDisplay();
3798  while(ReturnNextInactiveTrackElement(0, Next))
3799  {
3800  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3801  {
3802  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3803  {
3804  // only plot if on screen, to save time
3805  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3807  {
3808  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3809  }
3810  }
3811  }
3812  }
3813 
3814  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3815 
3816  NextTrackElementPtr = TrackVector.begin();
3817  while(ReturnNextTrackElement(0, Next))
3818  {
3819  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3820  {
3821  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3823  {
3824  if(Next.TrackType == Points)
3825  {
3826  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3827  }
3828  else if(Next.TrackType == SignalPost)
3829  {
3830  PlotSignal(9, Next, Disp);
3831  }
3832  else if(Next.TrackType == GapJump)
3833  {
3834  PlotGap(0, Next, Disp);
3835  }
3836  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3837  {
3838  PlotContinuation(0, Next, Disp);
3839  }
3840  else
3841  {
3842  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3843  }
3844  }
3845  }
3846  }
3847 
3848  if(BothPointFilletsAndBasicLCs)
3849  {
3851  while(ReturnNextInactiveTrackElement(4, Next))
3852  {
3853  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3854  {
3855  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3856  {
3857  // only plot if on screen, to save time, & OK as plotting one by one here
3858  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3860  {
3861  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3862  {
3863  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3864  }
3865  else
3866  {
3867  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3868  }
3869  }
3870  }
3871  }
3872  }
3873  }
3874  Disp->Update();
3875  Utilities->CallLogPop(468);
3876 }
3877 
3878 // ---------------------------------------------------------------------------
3879 
3880 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3881 {
3882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3883  if(UserGraphicVector.empty())
3884  {
3885  Utilities->CallLogPop(2175);
3886  return;
3887  }
3888  TUserGraphicItem UGI;
3889 
3890  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3891  {
3892  UGI = UserGraphicVectorAt(4, x);
3893  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3894  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3895  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3896  {
3897  Disp->PlotAndAddUserGraphic(0, UGI);
3898  }
3899  }
3900  Disp->Update();
3901  Utilities->CallLogPop(2176);
3902 }
3903 
3904 // ---------------------------------------------------------------------------
3905 
3906 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3907 /*
3908  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3909 */
3910 {
3911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3912 // need to change graphics back to black on white if have a dark background
3913  TColor OldTransparentColour = Utilities->clTransparent;
3914 
3916  {
3917  Utilities->clTransparent = TColor(0xFFFFFF); // white
3920  }
3921  TTrackElement Next;
3922 
3923  Bitmap->Canvas->CopyMode = cmSrcCopy;
3925  Graphics::TBitmap *GraphicOutput;
3926 
3927  while(ReturnNextInactiveTrackElement(2, Next))
3928  {
3929  GraphicOutput = Next.GraphicPtr;
3930  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3931  {
3932  if(Next.LocationName == "") // plot as named or unnamed (striped)
3933  {
3934  // default is not striped
3935  switch(Next.SpeedTag)
3936  {
3937  case 76: // t platform
3938  GraphicOutput = RailGraphics->gl76Striped;
3939  break;
3940 
3941  case 77: // h platform
3942  GraphicOutput = RailGraphics->bm77Striped;
3943  break;
3944 
3945  case 78: // v platform
3946  GraphicOutput = RailGraphics->bm78Striped;
3947  break;
3948 
3949  case 79: // r platform
3950  GraphicOutput = RailGraphics->gl79Striped;
3951  break;
3952 
3953  case 96: // concourse
3954  GraphicOutput = RailGraphics->ConcourseStriped;
3955  break;
3956 
3957  case 129: // v footbridge
3958  GraphicOutput = RailGraphics->gl129Striped;
3959  break;
3960 
3961  case 130: // h footbridge
3962  GraphicOutput = RailGraphics->gl130Striped;
3963  break;
3964 
3965  case 131: // non-station named loc
3966  GraphicOutput = RailGraphics->bmNameStriped;
3967  break;
3968 
3969  case 145: // v underpass
3970  GraphicOutput = RailGraphics->gl145Striped;
3971  break;
3972 
3973  case 146: // h underpass
3974  GraphicOutput = RailGraphics->gl146Striped;
3975  break;
3976 
3977  default:
3978  GraphicOutput = Next.GraphicPtr;
3979  break;
3980  }
3981  }
3982  if(Next.SpeedTag == 144) // level crossing
3983  {
3984  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3985  {
3986  GraphicOutput = RailGraphics->LCBothVer;
3987  }
3988  else
3989  {
3990  GraphicOutput = RailGraphics->LCBothHor;
3991  }
3992  }
3993  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3994  }
3995  }
3996 
3997  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3998 
3999 
4000  NextTrackElementPtr = TrackVector.begin();
4001  while(ReturnNextTrackElement(2, Next))
4002  {
4003  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4004  {
4005  if(Next.TrackType == Points) // plot both fillets
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4008  if(Next.SpeedTag < 28)
4009  {
4010  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4012  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4014  }
4015  else if(Next.SpeedTag < 132)
4016  {
4017  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4018  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4020  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4021  }
4022  else
4023  {
4024  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4025  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4026  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4027  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4028  }
4029  }
4030  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4031  {
4032  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4033  {
4034  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4035  }
4036  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4037  {
4038  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4039  }
4040  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4041  {
4042  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4043  }
4044  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4045  {
4046  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4047  }
4048  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4049  {
4050  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4051  }
4052  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4053  {
4054  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4055  }
4056  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4057  {
4058  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4059  }
4060  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4061  {
4062  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4063  }
4064  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4065  {
4066  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4067  }
4068  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4069  {
4070  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4071  }
4072  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4073  {
4074  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4075  }
4076  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4077  {
4078  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4079  }
4080  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4081  {
4082  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4083  }
4084  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4085  {
4086  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4087  }
4088  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4089  {
4090  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4091  }
4092  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4093  {
4094  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4095  }
4096  }
4097  // below added for version 0.6, only stop signals to be drawn
4098  else if(Next.TrackType == SignalPost)
4099  {
4100  for(int x = 0; x < 40; x++)
4101  {
4102  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4103  {
4104  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4105  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4106  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4107  int HOffset = 0;
4108  if(Next.SpeedTag > 73)
4109  {
4110  HOffset = 5;
4111  }
4112  else if(Next.SpeedTag == 71)
4113  {
4114  HOffset = 9;
4115  }
4116  int VOffset = 0;
4117  if(Next.SpeedTag == 69)
4118  {
4119  VOffset = 9;
4120  }
4121  else if(Next.SpeedTag == 72)
4122  {
4123  VOffset = 5;
4124  }
4125  else if(Next.SpeedTag == 74)
4126  {
4127  VOffset = 5;
4128  }
4129  Graphics::TBitmap *GraphicPtr;
4130  if(Next.SpeedTag > 71)
4131  {
4132  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4133  }
4134  else if(Next.SpeedTag < 70)
4135  {
4136  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4137  }
4138  else
4139  {
4140  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4141  }
4142  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4143  // plot special signal platform if present
4144  Graphics::TBitmap* SignalPlatformGraphic;
4145  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4146  {
4147  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4148  }
4149  // now plot signal (double yellow overwrites most of signal platform if present)
4150  // below amended for version 0.6
4152  {
4153  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4154  }
4155  else if(Next.SigAspect == TTrackElement::TwoAspect)
4156  {
4157  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4158  }
4159  else if(Next.SigAspect == TTrackElement::GroundSignal)
4160  {
4161  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4162  }
4163  else // 4 aspect
4164  {
4165  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4166  }
4167  break;
4168  }
4169  }
4170  }
4171  else
4172  {
4173  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4174  }
4175  }
4176  }
4177  if(OldTransparentColour != clB5G5R5)
4178  {
4179  Utilities->clTransparent = OldTransparentColour; // restore
4182  }
4183  Utilities->CallLogPop(1533);
4184 }
4185 
4186 // ---------------------------------------------------------------------------
4187 
4188 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4189 {
4190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4191  if(UserGraphicVector.empty())
4192  {
4193  Utilities->CallLogPop(2192);
4194  return;
4195  }
4196  else
4197  {
4198  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4199  {
4200  Bitmap->Canvas->CopyMode = cmSrcCopy;
4201  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4202  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4203  }
4204  }
4205  Utilities->CallLogPop(2193);
4206 }
4207 
4208 // ---------------------------------------------------------------------------
4209 
4210 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4211 /*
4212  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4213  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4214 */
4215 {
4216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4217 // need to change graphics back to black on white if have a dark background
4218  TColor OldTransparentColour = Utilities->clTransparent;
4219 
4221  {
4222  Utilities->clTransparent = TColor(0xFFFFFF); // white
4225  }
4226  TTrackElement Next;
4227 
4228  Bitmap->Canvas->CopyMode = cmSrcCopy;
4230  Graphics::TBitmap *GraphicOutput;
4231 
4232  while(ReturnNextInactiveTrackElement(3, Next))
4233  {
4234  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4235  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4236  {
4237  if(Next.SpeedTag == 144) // level crossing
4238  {
4239  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4240  if(BaseElement == 1) // hor element
4241  {
4242  if(Next.Attribute == 1) // open to trains
4243  {
4244  GraphicOutput = RailGraphics->LCBothHor;
4245  }
4246  else // plot as closed to trains if in any other state
4247  {
4248  GraphicOutput = RailGraphics->LCBothVer;
4249  }
4250  }
4251  else // vert element
4252  {
4253  if(Next.Attribute == 1) // open to trains
4254  {
4255  GraphicOutput = RailGraphics->LCBothVer;
4256  }
4257  else // plot as closed to trains if in any other state
4258  {
4259  GraphicOutput = RailGraphics->LCBothHor;
4260  }
4261  }
4262  }
4263  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4264  }
4265  }
4266 
4267  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4268 
4269  NextTrackElementPtr = TrackVector.begin();
4270  while(ReturnNextTrackElement(3, Next))
4271  {
4272  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4273  {
4274  if(Next.TrackType == Points) // plot active fillet
4275  {
4276  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4277  if(Next.SpeedTag < 28)
4278  {
4279  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4281  }
4282  else if(Next.SpeedTag < 132)
4283  {
4284  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4286  }
4287  else
4288  {
4289  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4291  }
4292  if(Next.Failed) //added at v2.13.0
4293  {
4294  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4296  }
4297 
4298  }
4299  else if(Next.TrackType == GapJump) // plot as connected
4300  {
4301  if(Next.SpeedTag == 88)
4302  {
4303  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4304  }
4305  else if(Next.SpeedTag == 89)
4306  {
4307  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4308  }
4309  else if(Next.SpeedTag == 90)
4310  {
4311  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4312  }
4313  else if(Next.SpeedTag == 91)
4314  {
4315  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4316  }
4317  else if(Next.SpeedTag == 92)
4318  {
4319  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4320  }
4321  else if(Next.SpeedTag == 93)
4322  {
4323  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4324  }
4325  else if(Next.SpeedTag == 94)
4326  {
4327  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4328  }
4329  else if(Next.SpeedTag == 95)
4330  {
4331  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4332  }
4333  }
4334  else if(Next.TrackType == SignalPost) //plot in correct colour
4335  {
4336  for(int x = 0; x < 40; x++)
4337  {
4338  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4339  {
4340  //plot blank first, then plot platform if present - (always not striped for operating railway)
4341  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4342  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4343  int HOffset = 0;
4344  if(Next.SpeedTag > 73)
4345  {
4346  HOffset = 5;
4347  }
4348  else if(Next.SpeedTag == 71)
4349  {
4350  HOffset = 9;
4351  }
4352  int VOffset = 0;
4353  if(Next.SpeedTag == 69)
4354  {
4355  VOffset = 9;
4356  }
4357  else if(Next.SpeedTag == 72)
4358  {
4359  VOffset = 5;
4360  }
4361  else if(Next.SpeedTag == 74)
4362  {
4363  VOffset = 5;
4364  }
4365  Graphics::TBitmap *GraphicPtr;
4366  if(Next.SpeedTag > 71)
4367  {
4368  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4369  }
4370  else if(Next.SpeedTag < 70)
4371  {
4372  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4373  }
4374  else
4375  {
4376  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4377  }
4378  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4379  // plot special signal platform if present
4380  Graphics::TBitmap* SignalPlatformGraphic;
4381  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4382  {
4383  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4384  }
4385  if(!Next.Failed)
4386  {
4387  // now plot signal (double yellow overwrites most of signal platform if present)
4388  // below amended for version 0.6
4390  {
4391  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4392  }
4393  else if(Next.SigAspect == TTrackElement::TwoAspect)
4394  {
4395  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4396  }
4397  else if(Next.SigAspect == TTrackElement::GroundSignal)
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4400  }
4401  else // 4 aspect
4402  {
4403  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4404  }
4405  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4406  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4407  {
4408  if(Next.SpeedTag == 68)
4409  {
4410  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4411  }
4412  if(Next.SpeedTag == 69)
4413  {
4414  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4415  }
4416  if(Next.SpeedTag == 70)
4417  {
4418  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4419  }
4420  if(Next.SpeedTag == 71)
4421  {
4422  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4423  }
4424  if(Next.SpeedTag == 72)
4425  {
4426  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4427  }
4428  if(Next.SpeedTag == 73)
4429  {
4430  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4431  }
4432  if(Next.SpeedTag == 74)
4433  {
4434  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4435  }
4436  if(Next.SpeedTag == 75)
4437  {
4438  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4439  }
4440  }
4441  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4442  {
4443  for(int x = 0; x < 40; x++)
4444  {
4445  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4446  {
4447  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4448  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4449  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4450  // plot special signal platform if present
4451  Graphics::TBitmap* SignalPlatformGraphic;
4452  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4453  {
4454  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4455  }
4456  // now plot signal
4457  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4458  break;
4459  }
4460  }
4461  }
4462  break;
4463  }
4464  else //added at v2.13.0
4465  {
4467  {
4468  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4469  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4470  }
4471  else
4472  {
4473  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4474  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4475  }
4476  break;
4477  }
4478  }
4479  }
4480  }
4481  else
4482  {
4483  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4484  if(Next.Failed) //added at v2.13.0
4485  {
4486  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4488  }
4489  }
4490  }
4491  }
4492  if(OldTransparentColour != clB5G5R5)
4493  {
4494  Utilities->clTransparent = OldTransparentColour; // restore
4497  }
4498  Utilities->CallLogPop(1701);
4499 }
4500 
4501 // ---------------------------------------------------------------------------
4502 
4503 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4504 {
4505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4506  for(unsigned int x = 0; x < TrackVector.size(); x++)
4507  {
4508  if(TrackElementAt(1093, x).TrackType == GapJump)
4509  {
4510  if(TrackElementAt(1094, x).Conn[0] > -1)
4511  {
4512  continue; // to next 'x' value as this element has already been set
4513  }
4514  // here if identify a GapJump element not yet set
4515  GapPos = x;
4516  GapHLoc = TrackElementAt(1095, x).HLoc;
4517  GapVLoc = TrackElementAt(1096, x).VLoc;
4518  // highlight it
4520  Utilities->CallLogPop(469);
4521  return(true);
4522  }
4523  }
4524  Utilities->CallLogPop(470);
4525  return(false);
4526 }
4527 
4528 // ---------------------------------------------------------------------------
4529 
4530 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4531 {
4532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4533  AnsiString(VLoc));
4534  int Position;
4535  TTrackElement TrackElement;
4536 
4537  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4538  {
4539  Utilities->CallLogPop(471);
4540  return(false); // not found
4541  }
4542  if(TrackElement.TrackType != GapJump)
4543  {
4544  Utilities->CallLogPop(472);
4545  return(false); // found something but not a gap
4546  }
4547  if(Position == GapPos)
4548  {
4549  Utilities->CallLogPop(473);
4550  return(false); // selected original gap
4551  }
4552  if(TrackElementAt(1097, Position).Conn[0] != -1)
4553  {
4554  Utilities->CallLogPop(474);
4555  return(false); // already selected
4556  }
4557  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4558  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4559  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4560  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4561 // now highlight the selected location
4562  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4563  Utilities->CallLogPop(475);
4564  return(true);
4565 }
4566 
4567 // ---------------------------------------------------------------------------
4568 
4569 bool TTrack::GapsUnset(int Caller)
4570 // returns true if there are gaps and any are unset
4571 {
4572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4573  if(TrackVector.size() == 0)
4574  {
4575  Utilities->CallLogPop(476);
4576  return(false);
4577  }
4578  for(unsigned int x = 0; x < TrackVector.size(); x++)
4579  {
4580  if(TrackElementAt(1102, x).TrackType == GapJump)
4581  {
4582  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4583  {
4584  Utilities->CallLogPop(477);
4585  return(true);
4586  }
4587  else // set, but may not have matching element, or that element may not be set
4588  {
4589  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4590  // check that the element pointed to by the gap link is a GapJump
4591  {
4592  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4593  Utilities->CallLogPop(1137);
4594  return(false);
4595  }
4596 // here if gap connection is itself a GapJump
4597  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4598  // check that the element pointed to by the gap link is a GapJump & that its gap link
4599  // points back to 'x'
4600  {
4601  Utilities->CallLogPop(478);
4602  return(true);
4603  }
4604 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4605  }
4606  } // if(TrackElementAt(, x).TrackType == GapJump)
4607 
4608  } // for x...
4609  Utilities->CallLogPop(479);
4610  return(false);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4618  for(unsigned int x = 0; x < TrackVector.size(); x++)
4619  {
4620  if(TrackElementAt(1110, x).TrackType == GapJump)
4621  {
4622  Utilities->CallLogPop(1105);
4623  return(false);
4624  }
4625  }
4626  Utilities->CallLogPop(1106);
4627  return(true);
4628 }
4629 
4630 // ---------------------------------------------------------------------------
4631 
4632 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4633 {
4634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4635  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4636  {
4637  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4638  {
4639  Utilities->CallLogPop(1107);
4640  return(false);
4641  }
4642  }
4643  for(unsigned int x = 0; x < TrackVector.size(); x++)
4644  {
4645  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4646  {
4647  Utilities->CallLogPop(1108);
4648  return(false);
4649  }
4650  }
4651  Utilities->CallLogPop(1109);
4652  return(true);
4653 }
4654 
4655 // ---------------------------------------------------------------------------
4656 
4658 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4659 // returns false otherwise or if there are no NamedLocationElements
4660 {
4661  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4662  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4663  {
4664  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4665  {
4666  if(InactiveTrackElementAt(139, x).LocationName == "")
4667  {
4668  Utilities->CallLogPop(1110);
4669  return(true);
4670  }
4671  }
4672  }
4673  for(unsigned int x = 0; x < TrackVector.size(); x++)
4674  {
4675  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4676  {
4677  if(TrackElementAt(1113, x).LocationName == "")
4678  {
4679  Utilities->CallLogPop(1111);
4680  return(true);
4681  }
4682  }
4683  }
4684  Utilities->CallLogPop(1112);
4685  return(false);
4686 }
4687 
4688 // ---------------------------------------------------------------------------
4689 
4690 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4691 {
4692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4693  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4694  Utilities->CallLogPop(480);
4695 }
4696 
4697 // ---------------------------------------------------------------------------
4698 
4700 {
4701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4702  if(TrackVector.size() == 0)
4703  {
4704  Utilities->CallLogPop(481);
4705  return;
4706  }
4707  for(unsigned int x = 0; x < TrackVector.size(); x++)
4708  {
4709  if(TrackElementAt(1114, x).TrackType == GapJump)
4710  {
4711  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4712  {
4713  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4714  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4715  {
4716  TrackElementAt(1118, x).Conn[0] = -1;
4717  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4718  continue; // to next 'x'
4719  }
4720 // here if gap connection is itself a GapJump
4721  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4722  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4723  // if not clear Conns & CLks
4724  {
4725  TrackElementAt(1121, x).Conn[0] = -1;
4726  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4727  continue; // to next 'x'
4728  }
4729 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4730 // hence no more action needed on these Conns & CLks
4731  }
4732  } // else //gap jump
4733 
4734  } // for x...
4735 // throw Exception("Test Exception");//test
4736  Utilities->CallLogPop(482);
4737 }
4738 
4739 // ---------------------------------------------------------------------------
4740 
4741 void TTrack::ResetSignals(int Caller)
4742 {
4743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4744  for(unsigned int x = 0; x < TrackVector.size(); x++)
4745  {
4746  if(TrackElementAt(1123, x).TrackType == SignalPost)
4747  {
4748  TrackElementAt(1124, x).Attribute = 0;
4749  TrackElementAt(1514, x).Failed = false;
4750  }
4751  }
4752  FailedSignalsVector.clear();
4753  Utilities->CallLogPop(483);
4754 }
4755 
4756 // ---------------------------------------------------------------------------
4757 
4758 void TTrack::ResetPoints(int Caller)
4759 {
4760  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4761  for(unsigned int x = 0; x < TrackVector.size(); x++)
4762  {
4763  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4764  {
4765  TrackElementAt(1126, x).Attribute = 0;
4766  TrackElementAt(1515, x).Failed = false;
4769  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4770  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4771  }
4772  }
4773  FailedPointsVector.clear();
4774  Utilities->CallLogPop(484);
4775 }
4776 
4777 // ---------------------------------------------------------------------------
4778 
4779 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4780 {
4781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4782  for(unsigned int x = 0; x < TrackVector.size(); x++)
4783  {
4784  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4785  {
4786  TrackElementAt(1556, x).Failed = false;
4788  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4789  }
4790  }
4791  TSRVector.clear();
4792  Utilities->CallLogPop(2550);
4793 }
4794 
4795 // ---------------------------------------------------------------------------
4796 
4797 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4798 {
4799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4800  if(TrackVector.empty())
4801  {
4802  TrackMap.clear();
4803  Utilities->CallLogPop(485);
4804  return(true);
4805  }
4806 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4807  THVPair TrackMapKeyPair;
4808 
4809  NewVector.clear();
4810  TTrackMapIterator TrackMapPtr;
4811 
4812  if(!TrackMap.empty())
4813  {
4814  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4815  {
4816  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4817  }
4818  }
4819  if(NewVector.size() != TrackMap.size())
4820  {
4821  throw Exception("Error - Map & Vector different sizes");
4822  }
4823  unsigned int NonZeroCount = 0;
4824 
4825  for(unsigned int x = 0; x < TrackVector.size(); x++)
4826  {
4827  if(TrackElementAt(1127, x).TrackType != Erase)
4828  {
4829  NonZeroCount++;
4830  }
4831  }
4832  if(NewVector.size() != NonZeroCount)
4833  {
4834  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4835  }
4837  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4838  TTrackMapEntry TrackMapEntry;
4839 
4840  for(unsigned int x = 0; x < TrackVector.size(); x++)
4841  {
4842  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4843  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4844  TrackMapEntry.first = TrackMapKeyPair;
4845  TrackMapEntry.second = x;
4846  if(!(TrackMap.insert(TrackMapEntry).second))
4847  {
4848  throw Exception("Error - map insertion failure, TrackVector in error");
4849  }
4850  }
4851 // All track now relocated in TrackVector, reset all Conns & CLks
4852  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4853  {
4854  for(unsigned int y = 0; y < 4; y++)
4855  {
4856  TrackElementAt(1130, x).Conn[y] = -1;
4857  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4858  }
4859  }
4860  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4861  CheckMapAndTrack(4); // test
4862  CheckMapAndInactiveTrack(4); // test
4863  CheckLocationNameMultiMap(8); // test
4864  if(!ResetGapsFromGapMap(1))
4865  {
4866  Utilities->CallLogPop(489);
4867  return(false);
4868  }
4869  Utilities->CallLogPop(490);
4870  return(true);
4871 }
4872 
4873 // ---------------------------------------------------------------------------
4874 
4875 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4876 {
4877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4878  GapMap.clear();
4879  THVPair GapMapKeyPair, GapMapValuePair;
4880  TGapMapEntry GapMapEntry;
4881 
4882  for(unsigned int x = 0; x < TrackVector.size(); x++)
4883  {
4884  if(TrackElementAt(1132, x).TrackType == GapJump)
4885  {
4886  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4887  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4888  GapMapEntry.first = GapMapKeyPair;
4889  if(TrackElementAt(1135, x).Conn[0] == -1)
4890  {
4891  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4892  }
4893  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4894  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4895  GapMapEntry.second = GapMapValuePair;
4896  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4897  {
4898  GapMap.insert(GapMapEntry);
4899  }
4900  }
4901  }
4902  Utilities->CallLogPop(492);
4903 }
4904 
4905 // ---------------------------------------------------------------------------
4906 
4907 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4908 {
4909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4910 
4911 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4912  LocError = false;
4913  bool TrackElementPositionsOK = true;
4914 
4915  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4916  {
4917  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4918  {
4919  continue; // skip blank elements
4920  }
4921 // check footcrossing linkages
4922  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4923  {
4924  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4925  {
4926  ShowMessage(
4927  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4928  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4929  "can't connect to an underpass or vice versa)");
4930  HLoc = TrackElementAt(1141, x).HLoc;
4931  VLoc = TrackElementAt(1142, x).VLoc;
4932  LocError = true;
4933  Utilities->CallLogPop(493);
4934  return(false);
4935  }
4936  }
4937  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4938  {
4939  if(TrackElementAt(1143, x).Link[y] <= 0)
4940  {
4941  continue; // no link
4942  }
4943  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4944  {
4945  continue; // buffer
4946  }
4947  if(TrackElementAt(1146, x).Config[y] == Gap)
4948  {
4949  continue; // gaps set later from GapMap
4950  }
4951  // get required H & V for track element joining link 'y'
4952  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4953  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4954  // find track element if present
4955  bool ConnectionFoundFlag;
4956  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4957  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4958  {
4959  ShowMessage("Can't have a track element adjacent to a continuation exit");
4960  HLoc = TrackElementAt(1152, x).HLoc;
4961  VLoc = TrackElementAt(1153, x).VLoc;
4962  LocError = true;
4963  if(FinalCall)
4964  {
4965  throw Exception("Error in final track linkage - continuation adjacent to another element");
4966  }
4967  Utilities->CallLogPop(1539);
4968  return(false);
4969  }
4970  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4971  {
4972  continue;
4973  }
4974  if(ConnectionFoundFlag)
4975  {
4976  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4977  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4978 
4979  bool ExitSignal = false;
4980  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
4981  {
4982  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
4983  {
4984  ExitSignal = true;
4985  }
4986  }
4987  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4988  {
4989  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4990  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4991  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4992  TrackElementPositionsOK = false;
4993  }
4994  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4995  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4996  {
4997  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4998  // need room for a train (2 elements) without fouling points or signals
4999  TrackElementPositionsOK = false;
5000  }
5001  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5002  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5003  {
5004  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5005  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5006  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5007  // be named but needs the adjacent element named too
5008  TrackElementPositionsOK = false;
5009  }
5010  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5011  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5012  {
5013  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5014  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5015  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5016  TrackElementPositionsOK = false;
5017  }
5018 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5019 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
5020  {
5021  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5022  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5023  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5024  TrackElementPositionsOK = false;
5025  }*/
5026  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5027  {
5028  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5029  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5030  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5031  TrackElementPositionsOK = false;
5032  }
5033  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5034  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5035  {
5036  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5037  TrackElementPositionsOK = false;
5038  }
5039  // if failed then set the invert values for the offending element
5040  if(!TrackElementPositionsOK)
5041  {
5042  HLoc = TrackElementAt(1183, x).HLoc;
5043  VLoc = TrackElementAt(1184, x).VLoc;
5044  LocError = true;
5045  if(FinalCall)
5046  {
5047  throw Exception("Error in track element positions in FinalCall");
5048  }
5049  Utilities->CallLogPop(494);
5050  return(false);
5051  }
5052  }
5053  // no 'else' here, if there's no link then will be picked up in 2nd pass
5054  }
5055  } // for(unsigned int x=0;x<TrackVector.size();x++)
5056 
5057 
5058 //2nd pass - looking for missing connections
5059  LocError = false;
5060  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5061  {
5062  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5063  {
5064  continue; // skip blank elements
5065  }
5066  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5067  {
5068  if(TrackElementAt(1440, x).Link[y] <= 0)
5069  {
5070  continue; // no link
5071  }
5072  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5073  {
5074  continue; // buffer
5075  }
5076  if(TrackElementAt(1443, x).Config[y] == Gap)
5077  {
5078  continue; // gaps set later from GapMap
5079  }
5080  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5081  {
5082  continue; //continuation
5083  }
5084  // get required H & V for track element joining link 'y'
5085  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5086  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5087  // find track element if present
5088  bool ConnectionFoundFlag;
5089  bool LinkMatchFound = false;
5090  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
5091  // if there isn't a connection set the invert values for the offending element
5092  if(ConnectionFoundFlag) //set the ConnLinkPos values
5093  {
5094  for(unsigned int a = 0; a < 4; a++)
5095  {
5096  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5097  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5098  {
5099  TrackElementAt(1182, x).ConnLinkPos[y] = a;
5100  // note - this ensures that if the connecting element is a leading point
5101  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5102  // (Points have the same link value for both [0] and [2])
5103  LinkMatchFound = true;
5104  break; // stop after first find or will find later link for leading point
5105  }
5106  }
5107  if(!LinkMatchFound)
5108  {
5109  HLoc = TrackElementAt(1446, x).HLoc;
5110  VLoc = TrackElementAt(1447, x).VLoc;
5111  LocError = true;
5112  if(FinalCall)
5113  {
5114  throw Exception("Error in final track linkage - - no matching link found");
5115  }
5116  Utilities->CallLogPop(495);
5117  return(false);
5118  }
5119  }
5120  else //error
5121  {
5122  HLoc = TrackElementAt(1185, x).HLoc;
5123  VLoc = TrackElementAt(1186, x).VLoc;
5124  LocError = true;
5125  if(FinalCall)
5126  {
5127  throw Exception("Error in final track linkage - connection not found");
5128  }
5129  Utilities->CallLogPop(2443);
5130  return(false);
5131  }
5132  }
5133  }
5134 //end of 2nd pass
5135 
5136  if(FinalCall)
5137  {
5139  }
5140 
5141 // confirmatiory checks that all ok - or throw error
5142  bool ConnErrorFlag = false;
5143 
5144  for(unsigned int x = 0; x < TrackVector.size(); x++)
5145  {
5146  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5147  {
5148  ConnErrorFlag = true;
5149  }
5150  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5151  {
5152  ConnErrorFlag = true;
5153  }
5154  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5155  {
5156  ConnErrorFlag = true;
5157  }
5158  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5159  {
5160  ConnErrorFlag = true;
5161  }
5162  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5163  {
5164  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5165  {
5166  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5167  {
5168  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5169  }
5170  }
5171  }
5172  }
5173  if(ConnErrorFlag)
5174  {
5175  if(FinalCall)
5176  {
5177  throw Exception("ConnError in LinkTrack - Final");
5178  }
5179  else
5180  {
5181  throw Exception("ConnError in LinkTrack - Precheck");
5182  }
5183  }
5184  bool CLkErrorFlag = false;
5185 
5186  for(unsigned int x = 0; x < TrackVector.size(); x++)
5187  {
5188  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5189  {
5190  CLkErrorFlag = true;
5191  }
5192  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5193  {
5194  CLkErrorFlag = true;
5195  }
5196  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5197  {
5198  CLkErrorFlag = true;
5199  }
5200  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5201  {
5202  CLkErrorFlag = true;
5203  }
5204  }
5205 
5206  if(CLkErrorFlag)
5207  {
5208  if(FinalCall)
5209  {
5210  throw Exception("CLkError in LinkTrack - Final");
5211  }
5212  else
5213  {
5214  throw Exception("CLkError in LinkTrack - Precheck");
5215  }
5216  }
5217 
5218 // set element lengths to min of 10m
5219  for(unsigned int x = 0; x < TrackVector.size(); x++)
5220  {
5221  if(TrackElementAt(1214, x).TrackType == Erase)
5222  {
5223  continue; // skip blank elements
5224  }
5225  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5226  {
5227  TrackElementAt(1216, x).Length01 = 10;
5228  }
5229  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5230  {
5231  TrackElementAt(1219, x).Length23 = 10;
5232  }
5233  }
5234 
5235  if(FinalCall) // ONLY at FinalCall, no point calling twice
5236  {
5237  CalcHLocMinEtc(3);
5238  }
5239 
5240  Utilities->CallLogPop(497);
5241  return(true);
5242 }
5243 
5244 // ---------------------------------------------------------------------------
5245 
5246 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5247 {
5248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5249  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5250  {
5251  if(TrackElementAt(1220, x).TrackType == Erase)
5252  {
5253  continue; // skip blank elements
5254 
5255  }
5256 // check footcrossing linkages
5257  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5258  {
5259  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5260  {
5261  Utilities->CallLogPop(1127);
5262  return(false);
5263  }
5264  }
5265  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5266  {
5267  if(TrackElementAt(1223, x).Link[y] <= 0)
5268  {
5269  continue; // no link
5270  }
5271  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5272  {
5273  continue; // buffer
5274  }
5275  if(TrackElementAt(1226, x).Config[y] == Gap)
5276  {
5277  continue; // gaps set later from GapMap
5278 
5279  }
5280  // get required H & V for track element joining link 'y'
5281  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5282  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5283  // find track element if present
5284  bool ConnectionFoundFlag;
5285  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5286  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5287  {
5288  if(FinalCall)
5289  {
5290  throw Exception("Error in final track linkage - continuation adjacent to another element");
5291  }
5292  Utilities->CallLogPop(1540);
5293  return(false);
5294  }
5295  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5296  {
5297  continue;
5298  }
5299  if(ConnectionFoundFlag)
5300  {
5301  TrackElementAt(1234, x).Conn[y] = VecPos;
5302  bool LinkFoundFlag = false;
5303  // find connecting link in the newly found track element if there is one & make checks
5304  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5305  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5306  {
5307  Utilities->CallLogPop(1541);
5308  return(false);
5309  }
5310  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5311  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5312  {
5313  Utilities->CallLogPop(1542);
5314  return(false);
5315  }
5316  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5317  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5318  {
5319  Utilities->CallLogPop(1543);
5320  return(false);
5321  }
5322  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5323  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5324  {
5325  Utilities->CallLogPop(1981);
5326  return(false);
5327  }
5328 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5329  else if(TrackElementAt(, x).TrackType == Continuation)
5330  {
5331  int H = TrackElementAt(, x).HLoc;
5332  int V = TrackElementAt(, x).VLoc;
5333  bool FoundFlag = false;
5334  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5335  if(FoundFlag)
5336  {
5337  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5338  {
5339  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5340  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5341  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5342  if(FoundFlag)
5343  {
5344  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5345  {
5346  Utilities->CallLogPop();
5347  return false;
5348  }
5349  }
5350  else
5351  {
5352  Utilities->CallLogPop();
5353  return false;
5354  }
5355  }
5356  }
5357  }
5358 */
5359  for(unsigned int a = 0; a < 4; a++)
5360  {
5361  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5362  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5363  {
5364  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5365  // note - this ensures that if the connecting element is a leading point
5366  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5367  // (Points have the same link value for both [0] and [2])
5368  LinkFoundFlag = true;
5369  break; // stop after first find or will find later link for leading point
5370  }
5371  }
5372  if(!LinkFoundFlag)
5373  {
5374  if(FinalCall)
5375  {
5376  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5377  }
5378  Utilities->CallLogPop(1128);
5379  return(false);
5380  }
5381  }
5382  else // if(ConnectionFoundFlag)
5383  {
5384  if(FinalCall)
5385  {
5386  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5387  }
5388  Utilities->CallLogPop(1129);
5389  return(false);
5390  }
5391  }
5392  } // for(unsigned int x=0;x<TrackVector.size();x++)
5393 
5394  if(FinalCall)
5395  {
5397  }
5398 // final check
5399  bool ConnErrorFlag = false;
5400 
5401  for(unsigned int x = 0; x < TrackVector.size(); x++)
5402  {
5403  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5404  {
5405  ConnErrorFlag = true;
5406  }
5407  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5408  {
5409  ConnErrorFlag = true;
5410  }
5411  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5412  {
5413  ConnErrorFlag = true;
5414  }
5415  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5416  {
5417  ConnErrorFlag = true;
5418  }
5419  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5420  {
5421  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5422  {
5423  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5424  {
5425  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5426  }
5427  }
5428  }
5429  }
5430  if(ConnErrorFlag)
5431  {
5432  if(FinalCall)
5433  {
5434  throw Exception("ConnError in LinkTrack - Final");
5435  }
5436  else
5437  {
5438  throw Exception("ConnError in LinkTrack - Precheck");
5439  }
5440  }
5441  bool CLkErrorFlag = false;
5442 
5443  for(unsigned int x = 0; x < TrackVector.size(); x++)
5444  {
5445  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5446  {
5447  CLkErrorFlag = true;
5448  }
5449  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5450  {
5451  CLkErrorFlag = true;
5452  }
5453  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5454  {
5455  CLkErrorFlag = true;
5456  }
5457  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5458  {
5459  CLkErrorFlag = true;
5460  }
5461  }
5462 
5463  if(CLkErrorFlag)
5464  {
5465  if(FinalCall)
5466  {
5467  throw Exception("CLkError in LinkTrack - Final");
5468  }
5469  else
5470  {
5471  throw Exception("CLkError in LinkTrack - Precheck");
5472  }
5473  }
5474 // set element lengths to min of 10m
5475  for(unsigned int x = 0; x < TrackVector.size(); x++)
5476  {
5477  if(TrackElementAt(1284, x).TrackType == Erase)
5478  {
5479  continue; // skip blank elements
5480  }
5481  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5482  {
5483  TrackElementAt(1286, x).Length01 = 10;
5484  }
5485  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5486  {
5487  TrackElementAt(1289, x).Length23 = 10;
5488  }
5489  }
5490 
5491  if(FinalCall) // ONLY at FinalCall, no point calling twice
5492  {
5493  CalcHLocMinEtc(7);
5494  }
5495  Utilities->CallLogPop(1130);
5496  return(true);
5497 }
5498 
5499 // ---------------------------------------------------------------------------
5500 
5501 bool TTrack::IsTrackLinked(int Caller) // not used any more
5502 {
5503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5504  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5505  {
5506  if(TrackElementAt(1290, x).TrackType == Erase)
5507  {
5508  Utilities->CallLogPop(498);
5509  return(false);
5510  }
5511 // check foot linkages
5512  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5513  {
5514  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5515  {
5516  Utilities->CallLogPop(499);
5517  return(false);
5518  }
5519  }
5520  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5521  {
5522  if(TrackElementAt(1293, x).Link[y] <= 0)
5523  {
5524  continue; // no link
5525  }
5526  if(TrackElementAt(1294, x).Config[y] == End)
5527  {
5528  continue; // buffer or continuation
5529  }
5530  if(TrackElementAt(1295, x).Config[y] == Gap)
5531  {
5532  continue; // gaps set later from GapMap
5533 
5534  }
5535  // get required H & V for track element joining link 'y'
5536  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5537  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5538  // find track element if present
5539  bool ConnectionFoundFlag = false;
5540  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5541  if(ConnectionFoundFlag)
5542  {
5543  TrackElementAt(1300, x).Conn[y] = VecPos;
5544  // find connecting link in the newly found track element if there is one & make buffer check
5545  bool LinkFoundFlag = false;
5546  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5547  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5548  {
5549  Utilities->CallLogPop(500);
5550  return(false);
5551  }
5552  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5553  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5554  {
5555  Utilities->CallLogPop(501);
5556  return(false);
5557  }
5558  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5559  {
5560  Utilities->CallLogPop(502);
5561  return(false);
5562  }
5563  else
5564  {
5565  for(unsigned int a = 0; a < 4; a++)
5566  {
5567  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5568  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5569  {
5570  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5571  // note - this ensures that if the connecting element is a leading point
5572  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5573  // (Points have the same link value for both [0] and [2])
5574  LinkFoundFlag = true;
5575  break; // stop after first find or will find later link for leading point
5576  }
5577  }
5578  }
5579  if(!LinkFoundFlag)
5580  {
5581  Utilities->CallLogPop(503);
5582  return(false);
5583  }
5584  }
5585  else // if(ConnectionFoundFlag)
5586  {
5587  Utilities->CallLogPop(504);
5588  return(false);
5589  }
5590  }
5591  } // for(unsigned int x=0;x<TrackVector.size();x++)
5592 
5593 // final check
5594  bool ConnErrorFlag = false;
5595 
5596  for(unsigned int x = 0; x < TrackVector.size(); x++)
5597  {
5598  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5599  {
5600  ConnErrorFlag = true;
5601  }
5602  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5603  {
5604  ConnErrorFlag = true;
5605  }
5606  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5607  {
5608  ConnErrorFlag = true;
5609  }
5610  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5611  {
5612  ConnErrorFlag = true;
5613  }
5614  }
5615  if(ConnErrorFlag)
5616  {
5617  Utilities->CallLogPop(505);
5618  return(false);
5619  }
5620  bool CLkErrorFlag = false;
5621 
5622  for(unsigned int x = 0; x < TrackVector.size(); x++)
5623  {
5624  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5625  {
5626  CLkErrorFlag = true;
5627  }
5628  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5629  {
5630  CLkErrorFlag = true;
5631  }
5632  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5633  {
5634  CLkErrorFlag = true;
5635  }
5636  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5637  {
5638  CLkErrorFlag = true;
5639  }
5640  }
5641 
5642  if(CLkErrorFlag)
5643  {
5644  Utilities->CallLogPop(506);
5645  return(false);
5646  }
5647  Utilities->CallLogPop(507);
5648  return(true);
5649 }
5650 
5651 // ---------------------------------------------------------------------------
5652 
5654 {
5655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5656  int Position1, Position2;
5657  TTrackElement TrackElement1, TrackElement2;
5658  TGapMapIterator GapMapPtr;
5659 
5660  if(!GapMap.empty())
5661  {
5662  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5663  {
5664  int HLoc1 = GapMapPtr->first.first;
5665  int VLoc1 = GapMapPtr->first.second;
5666  int HLoc2 = GapMapPtr->second.first;
5667  int VLoc2 = GapMapPtr->second.second;
5668  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5669  {
5670  throw Exception("Failed to find H & V for gap1, GapMap in error");
5671  }
5672  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5673  {
5674  throw Exception("Failed to find H & V for gap2, GapMap in error");
5675  }
5676  if(TrackElementAt(9, Position1).TrackType != GapJump)
5677  {
5678  throw Exception("Element at Pos1 not a gap, GapMap in error");
5679  }
5680  if(TrackElementAt(10, Position2).TrackType != GapJump)
5681  {
5682  throw Exception("Element at Pos2 not a gap, GapMap in error");
5683  }
5684  TrackElementAt(11, Position1).Conn[0] = Position2;
5685  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5686  TrackElementAt(13, Position2).Conn[0] = Position1;
5687  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5688  }
5689  }
5690  Utilities->CallLogPop(510);
5691  return(true);
5692 }
5693 
5694 // ---------------------------------------------------------------------------
5695 
5696 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5697 {
5698 // TIMPair MapEntry;
5699  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5700  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5701  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5702  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5703  TLocationNameMultiMapEntry LocationNameEntry;
5704 
5705  LocationNameEntry.first = TrackElement.LocationName;
5706  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5707  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5708  {
5709 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5710 // could arise when loading old railways with multiple NonStationNamedLocs
5711  bool FoundFlag = false;
5712  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5713  if(FoundFlag)
5714  {
5715  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5716  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5717  {
5718  Utilities->CallLogPop(1813);
5719  return;
5720  }
5721  }
5722  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5723  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5724  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5725  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5726  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5727  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5728  if(TrackElement.FixedNamedLocationElement)
5729  {
5730  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5731  LocationNameMultiMap.insert(LocationNameEntry);
5732  }
5733  if(TrackElement.HLoc < HLocMin)
5734  {
5735  HLocMin = TrackElement.HLoc;
5736  }
5737  if(TrackElement.HLoc > HLocMax)
5738  {
5739  HLocMax = TrackElement.HLoc;
5740  }
5741  if(TrackElement.VLoc < VLocMin)
5742  {
5743  VLocMin = TrackElement.VLoc;
5744  }
5745  if(TrackElement.VLoc > VLocMax)
5746  {
5747  VLocMax = TrackElement.VLoc;
5748  }
5749  }
5750  else
5751  {
5752 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5753 // shouldn't arise but leave in as a safeguard
5754  bool FoundFlag = false;
5755  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5756  if(FoundFlag)
5757  {
5758  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5759  {
5760  Utilities->CallLogPop(1814);
5761  return;
5762  }
5763  }
5764  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5765  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5766  {
5767  TrackMapKeyPair.first = TrackElement.HLoc;
5768  TrackMapKeyPair.second = TrackElement.VLoc;
5769  TrackMapEntry.first = TrackMapKeyPair;
5770  TrackMapEntry.second = TrackVector.size() - 1;
5771  TrackMap.insert(TrackMapEntry);
5772  if(TrackElement.FixedNamedLocationElement)
5773  {
5774  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5775  LocationNameMultiMap.insert(LocationNameEntry);
5776  }
5777  if(TrackElement.HLoc < HLocMin)
5778  {
5779  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5780  }
5781  if(TrackElement.HLoc > HLocMax)
5782  {
5783  HLocMax = TrackElement.HLoc;
5784  }
5785  if(TrackElement.VLoc < VLocMin)
5786  {
5787  VLocMin = TrackElement.VLoc;
5788  }
5789  if(TrackElement.VLoc > VLocMax)
5790  {
5791  VLocMax = TrackElement.VLoc;
5792  }
5793  }
5794  }
5795 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5796 // CheckMapAndInactiveTrack(6);//test
5797 
5798 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5799 // with the Platforms until layout fully loaded
5800  Utilities->CallLogPop(511);
5801 }
5802 
5803 // ---------------------------------------------------------------------------
5804 
5805 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5806 {
5807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5808  AnsiString(VLoc));
5809  THVPair TrackMapKeyPair;
5810 
5811  FoundFlag = false;
5812  TTrackMapIterator TrackMapPtr;
5813 
5814  TrackMapKeyPair.first = HLoc;
5815  TrackMapKeyPair.second = VLoc;
5816  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5817  if(TrackMapPtr == TrackMap.end())
5818  {
5819  Utilities->CallLogPop(512);
5820  return(-1); // nothing found
5821  }
5822  else
5823  {
5824  FoundFlag = true;
5825  Utilities->CallLogPop(513);
5826  return(TrackMapPtr->second);
5827  }
5828 }
5829 
5830 // ---------------------------------------------------------------------------
5831 
5832 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5833 {
5834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5835  AnsiString(VLoc));
5836  THVPair TrackMapKeyPair;
5837  TTrackMapIterator TrackMapPtr;
5838 
5839  TrackMapKeyPair.first = HLoc;
5840  TrackMapKeyPair.second = VLoc;
5841  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5842  if(TrackMapPtr == TrackMap.end())
5843  {
5844  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5845  throw Exception(Message);
5846  }
5847  else
5848  {
5849  Utilities->CallLogPop(1943);
5850  return(TrackElementAt(871, TrackMapPtr->second));
5851  }
5852 }
5853 
5854 // ---------------------------------------------------------------------------
5855 
5856 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5857 { //modded at v2.9.2 to make Map & Vector references
5858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5859  AnsiString(VLoc));
5860  THVPair MapKeyPair;
5861  TTrackMapIterator MapPtr;
5862 
5863  MapKeyPair.first = HLoc;
5864  MapKeyPair.second = VLoc;
5865  MapPtr = Map.find(MapKeyPair);
5866  if(MapPtr == Map.end())
5867  {
5868  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5869  throw Exception(Message);
5870  }
5871  else
5872  {
5873  Utilities->CallLogPop(2280);
5874  return(Vector.at(MapPtr->second));
5875  }
5876 }
5877 
5878 // ---------------------------------------------------------------------------
5879 
5881 {
5882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5883  AnsiString(VLoc));
5884  THVPair InactiveTrackMapKeyPair;
5885  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5886 
5887  InactiveTrackMapKeyPair.first = HLoc;
5888  InactiveTrackMapKeyPair.second = VLoc;
5889  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5890  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5891  {
5892  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5893  throw Exception(Message);
5894  }
5895  else
5896  {
5897  Utilities->CallLogPop(1949);
5898  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5899  }
5900 }
5901 
5902 // ---------------------------------------------------------------------------
5903 
5904 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5905 {
5906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5907  bool Present = true;
5908  THVPair TrackMapKeyPair;
5909  TTrackMapIterator TrackMapPtr;
5910 
5911  TrackMapKeyPair.first = HLoc;
5912  TrackMapKeyPair.second = VLoc;
5913  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5914  if(TrackMapPtr == TrackMap.end())
5915  {
5916  Present = false;
5917  }
5918  Utilities->CallLogPop(2057);
5919  return(Present);
5920 }
5921 
5922 // ---------------------------------------------------------------------------
5923 
5924 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5925 {
5926  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5927  AnsiString(VLoc));
5928  bool Present = true;
5929  THVPair InactiveTrackMapKeyPair;
5930  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5931 
5932  InactiveTrackMapKeyPair.first = HLoc;
5933  InactiveTrackMapKeyPair.second = VLoc;
5934  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5935  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5936  {
5937  Present = false;
5938  }
5939  Utilities->CallLogPop(2058);
5940  return(Present);
5941 }
5942 
5943 // ---------------------------------------------------------------------------
5944 
5945 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5946 // max number of elements is 2, for platforms
5947 // note that both elements of RetPair may be the same, if only one present in map
5948 {
5949  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5950  AnsiString(VLoc));
5951  THVPair InactiveTrackMapKeyPair;
5952  TIMPair RetPair;
5953  TInactiveTrackRange InactiveTrackRange;
5954 
5955  FoundFlag = false;
5956  InactiveTrackMapKeyPair.first = HLoc;
5957  InactiveTrackMapKeyPair.second = VLoc;
5958  if(InactiveTrack2MultiMap.empty())
5959  {
5960  RetPair.first = 0;
5961  RetPair.second = 0;
5962  Utilities->CallLogPop(1815);
5963  return(RetPair); // map empty
5964  }
5965  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5966  if(InactiveTrackRange.first == InactiveTrackRange.second)
5967  {
5968  RetPair.first = 0;
5969  RetPair.second = 0;
5970  Utilities->CallLogPop(514);
5971  return(RetPair); // nothing found
5972  }
5973  else
5974  {
5975  RetPair.first = InactiveTrackRange.first->second;
5976  RetPair.second = (--InactiveTrackRange.second)->second;
5977  FoundFlag = true;
5978  Utilities->CallLogPop(515);
5979  return(RetPair);
5980  }
5981 }
5982 
5983 // ---------------------------------------------------------------------------
5984 
5985 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
5986 {
5987 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5989  AnsiString(DivergingPosition));
5990  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5991  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5992  int SpeedTag1 = T1.SpeedTag;
5993  int SpeedTag2 = T2.SpeedTag;
5994 
5995  if((T1.Attribute) != (T2.Attribute))
5996  {
5997  Utilities->CallLogPop(516);
5998  return(false);
5999  }
6000  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6001  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6002  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6003  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6004  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6005  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6006  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6007  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6008  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6009  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6010  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6011  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6012  {
6013  Utilities->CallLogPop(517);
6014  return(true);
6015  }
6016  else
6017  {
6018  Utilities->CallLogPop(518);
6019  return(false);
6020  }
6021 }
6022 
6023 // ---------------------------------------------------------------------------
6024 
6025 /*
6026  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6027  {
6028  if(lower.second < higher.second) return true;
6029  else if(lower.second > higher.second) return false;
6030  else if(lower.second == higher.second)
6031  {
6032  if(lower.first < higher.first) return true;
6033  }
6034  return false;
6035  }
6036 */
6037 // ---------------------------------------------------------------------------
6038 
6039 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6040 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6041 {
6042  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6043  if(TrackElement.TrackType != GapJump)
6044  {
6045  throw Exception("Error, Wrong track type in PlotGap");
6046  }
6047  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6048  {
6049  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6050  }
6051  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6052  {
6053  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6054  }
6055  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6056  {
6057  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6058  }
6059  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6060  {
6061  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6062  }
6063  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6064  {
6065  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6066  }
6067  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6068  {
6069  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6070  }
6071  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6072  {
6073  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6074  }
6075  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6076  {
6077  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6078  }
6079  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6080  {
6081  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6082  }
6083  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6084  {
6085  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6086  }
6087  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6088  {
6089  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6090  }
6091  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6092  {
6093  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6094  }
6095  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6096  {
6097  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6098  }
6099  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6100  {
6101  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6102  }
6103  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6104  {
6105  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6106  }
6107  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6108  {
6109  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6110  }
6111  Utilities->CallLogPop(1101);
6112 }
6113 
6114 // ---------------------------------------------------------------------------
6115 
6116 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6117 {
6118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6119  TrackElement.PlotVariableTrackElement(7, Disp);
6120  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6121  {
6122  THVPair PosPair;
6123  PosPair.first = TrackElement.HLoc;
6124  PosPair.second = TrackElement.VLoc;
6125  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6126  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6127  {
6128  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6129  }
6130  }
6131  Utilities->CallLogPop(2403);
6132 }
6133 
6134 // ---------------------------------------------------------------------------
6135 
6136 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6137 {
6138  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6139  if(TrackElement.TrackType != Points)
6140  {
6141  throw Exception("Error, Wrong track type in PlotPoints");
6142  }
6143  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6144  TrackElement.PlotVariableTrackElement(4, Disp);
6145  if(BothFillets)
6146  {
6147  if(TrackElement.SpeedTag < 28)
6148  {
6149  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6150  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6151  }
6152  else if(TrackElement.SpeedTag < 132)
6153  {
6154  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6155  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6156  }
6157  else
6158  {
6159  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6160  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6161  }
6162  }
6163  else if(!TrackElement.Failed) //not failed
6164  {
6165  if(TrackElement.SpeedTag < 28)
6166  {
6167  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6168  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6169  }
6170  else if(TrackElement.SpeedTag < 132)
6171  {
6172  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6173  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6174  }
6175  else
6176  {
6177  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6178  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6179  }
6180  }
6181  else //failed in fixed position
6182  {
6183  if(TrackElement.SpeedTag < 28)
6184  {
6185  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6186  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6187  }
6188  else if(TrackElement.SpeedTag < 132)
6189  {
6190  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6191  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6192  }
6193  else
6194  {
6195  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6196  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6197  }
6198  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6199  }
6200 // replot platform if required
6201  TIMPair IMPair;
6202  bool FoundFlag;
6203 
6204  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6205  if(FoundFlag)
6206  {
6207  // only one platform possible at points so only need to plot IMPair.first
6208  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6209  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6210  }
6211  Utilities->CallLogPop(519);
6212 }
6213 
6214 // ---------------------------------------------------------------------------
6215 
6216 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6217 {
6218 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6219  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6220  if(TrackElement.TrackType != SignalPost)
6221  {
6222  throw Exception("Error, Wrong track type in PlotSignal");
6223  }
6224  if(!TrackElement.Failed) //added at v2.13.0
6225  {
6226  for(int x = 0; x < 40; x++)
6227  {
6228  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6229  {
6230  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6231  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6232  // in case existing signal is a double yellow
6233  // plot platforms if present
6234  // Graphics::TBitmap* SignalPlatformGraphic;
6235  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6236  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6237  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6238  // to not be plotted with the above function.
6239  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6240  // now plot signal (double yellow overwrites most of signal platform if present)
6241  // additions at version 0.6 for other aspects & ground sigs
6242  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6243  {
6244  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6245  }
6246  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6247  {
6248  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6249  }
6250  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6251  {
6252  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6253  }
6254  else // 4 aspect
6255  {
6256  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6257  }
6258  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6259  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6260  {
6261  if(TrackElement.SpeedTag == 68)
6262  {
6263  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6264  }
6265  if(TrackElement.SpeedTag == 69)
6266  {
6267  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6268  }
6269  if(TrackElement.SpeedTag == 70)
6270  {
6271  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6272  }
6273  if(TrackElement.SpeedTag == 71)
6274  {
6275  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6276  }
6277  if(TrackElement.SpeedTag == 72)
6278  {
6279  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6280  }
6281  if(TrackElement.SpeedTag == 73)
6282  {
6283  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6284  }
6285  if(TrackElement.SpeedTag == 74)
6286  {
6287  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6288  }
6289  if(TrackElement.SpeedTag == 75)
6290  {
6291  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6292  }
6293  }
6294  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6295  // ground signal calling on, need to use normal proceed aspect
6296  {
6297  for(int x = 0; x < 40; x++)
6298  {
6299  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6300  {
6301  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6302  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6303  // plot special signal platform if present
6304  Graphics::TBitmap* SignalPlatformGraphic;
6305  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6306  // now plot signal
6307  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6308  }
6309  }
6310  }
6311  break;
6312  }
6313  }
6314  }
6315  else //failed added at v2.13.0
6316  {
6317  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6318  {
6319  for(int x = 0; x < 8; x++)
6320  {
6321  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6322  {
6323  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6324  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6325  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6326  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6327  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6328  break;
6329  }
6330  }
6331  }
6332  else
6333  {
6334  for(int x = 0; x < 8; x++)
6335  {
6336  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6337  {
6338  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6339  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6340  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6341  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6342  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6343  break;
6344  }
6345  }
6346  }
6347  }
6348  Utilities->CallLogPop(520);
6349 }
6350 
6351 // ---------------------------------------------------------------------------
6352 
6353 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6354 {
6355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6356  bool FoundFlag;
6357  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6358 
6359  if(!FoundFlag)
6360  {
6361  Utilities->CallLogPop(2112);
6362  return;
6363  }
6364  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6365  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6366 
6367  // don't want 'else if' for the below as may need to plot 2 platforms
6368  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6369  {
6370  if(IAElement1.LocationName == "") // '2' will be same
6371  {
6372  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6373  }
6374  else
6375  {
6376  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6377  }
6378  }
6379  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6380  {
6381  if(IAElement1.LocationName == "") // '2' will be same
6382  {
6383  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6384  }
6385  else
6386  {
6387  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6388  }
6389  }
6390  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6391  {
6392  if(IAElement1.LocationName == "") // '2' will be same
6393  {
6394  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6395  }
6396  else
6397  {
6398  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6399  }
6400  }
6401  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6402  {
6403  if(IAElement1.LocationName == "") // '2' will be same
6404  {
6405  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6406  }
6407  else
6408  {
6409  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6410  }
6411  }
6412  Utilities->CallLogPop(2113);
6413 }
6414 
6415 // ---------------------------------------------------------------------------
6416 
6417 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6418 {
6419 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6420  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6421  AnsiString(VLoc));
6422 // find topmost LC, opening them all (to trains) in turn
6423  int UpStep = 0;
6424 
6425  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6426  {
6427  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6428  UpStep--;
6429  }
6430 // now find bottommost LC, opening them all (to trains) in turn
6431  int DownStep = 1;
6432 
6433  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6434  {
6435  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6436  DownStep++;
6437  }
6438 // find leftmost LC, opening them all (to trains) in turn
6439  int LeftStep = 0;
6440 
6441  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6442  {
6443  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6444  LeftStep--;
6445  }
6446 // now find rightmost LC, opening them all (to trains) in turn
6447  int RightStep = 1;
6448 
6449  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6450  {
6451  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6452  RightStep++;
6453  }
6454  Utilities->CallLogPop(1915);
6455 }
6456 
6457 // ---------------------------------------------------------------------------
6458 
6459 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6460 {
6461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6462 // work upwards setting all to manual
6463  int UpStep = -1;
6464 
6465  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6466  {
6467  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6468  UpStep--;
6469  }
6470 // work downwards setting all to manual
6471  int DownStep = 1;
6472 
6473  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6474  {
6475  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6476  DownStep++;
6477  }
6478 // work leftwards setting all to manual
6479  int LeftStep = -1;
6480 
6481  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6482  {
6483  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6484  LeftStep--;
6485  }
6486 // work rightwards setting all to manual
6487  int RightStep = 1;
6488 
6489  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6490  {
6491  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6492  RightStep++;
6493  }
6494  Utilities->CallLogPop(2242);
6495 }
6496 
6497 // ---------------------------------------------------------------------------
6498 
6499 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6500 {
6501  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6503  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6504  {
6505  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6506  {
6507  BarriersDownVector.at(x).TypeOfRoute = 2;
6508  break;
6509  }
6510  }
6511  Utilities->CallLogPop(2243);
6512 }
6513 
6514 // ---------------------------------------------------------------------------
6515 
6516 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6517 {
6518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6519 // work upwards
6520  int UpStep = 0; //start with this location
6521 
6522  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6523  {
6524  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6525  {
6526  Utilities->CallLogPop(2244);
6527  return(true);
6528  }
6529  UpStep--;
6530  }
6531 // work downwards
6532  int DownStep = 1;
6533 
6534  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6535  {
6536  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6537  {
6538  Utilities->CallLogPop(2245);
6539  return(true);
6540  }
6541  DownStep++;
6542  }
6543 // work leftwards
6544  int LeftStep = -1;
6545 
6546  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6547  {
6548  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6549  {
6550  Utilities->CallLogPop(2246);
6551  return(true);
6552  }
6553  LeftStep--;
6554  }
6555 // work rightwards
6556  int RightStep = 1;
6557 
6558  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6559  {
6560  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6561  {
6562  Utilities->CallLogPop(2247);
6563  return(true);
6564  }
6565  RightStep++;
6566  }
6567  Utilities->CallLogPop(2248);
6568  return(false);
6569 }
6570 
6571 // ---------------------------------------------------------------------------
6572 
6573 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6574 {
6575  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6576  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6577  {
6578  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6579  {
6580  BDVectorPos = x;
6581  Utilities->CallLogPop(2249);
6582  return(true);
6583  }
6584  }
6585  BDVectorPos = -1;
6586  Utilities->CallLogPop(2250);
6587  return(false);
6588 }
6589 
6590 // ---------------------------------------------------------------------------
6591 
6592 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6593 // open to trains
6594 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6595 {
6596  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6597  AnsiString(VLoc));
6598  if(!IsLCAtHV(4, HLoc, VLoc))
6599  {
6600  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6601  }
6602  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6603  {
6604  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6605  }
6606 // check for adjacent LCs & if so open (to trains)
6607  if(BaseElementSpeedTag == 1) // hor track element
6608  {
6609  // find topmost LC, opening them all (to trains) in turn
6610  int UpStep = 0;
6611  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6612  {
6613  UpStep--;
6614  }
6615  UpStep++;
6616  // now find bottommost LC, opening them all (to trains) in turn
6617  int DownStep = 1;
6618  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6619  {
6620  DownStep++;
6621  }
6622  DownStep--;
6623  // now plot graphics, UpStep is smallest & DownStep largest
6624  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6625  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6626  Graphics::TBitmap *RouteGraphic;
6627  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6628  if(TypeOfRoute == 1)
6629  {
6630  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6631  }
6632  else if(TypeOfRoute == 0)
6633  {
6634  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6635  }
6636  else //manual - no route
6637  {
6638  RouteGraphic = BaseGraphic;
6639  }
6640 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6641 // LinkSigRouteGraphicsPtr[1] ver }
6642 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6643 // LinkNonSigRouteGraphicsPtr[1] ver }
6644 
6645  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6646  {
6647  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6648  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6649  if(!Manual)
6650  {
6651  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6652  }
6653  else
6654  {
6655  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6656  }
6657  }
6658  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6659  {
6660  if(UpStep == 0)
6661  {
6662  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6663  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6664  if(!Manual)
6665  {
6666  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6667  }
6668  else
6669  {
6670  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6671  }
6672  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6673  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6674  if(!Manual)
6675  {
6676  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6677  }
6678  else
6679  {
6680  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6681  }
6682  }
6683  else
6684  {
6685  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6686  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6687  if(!Manual)
6688  {
6689  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6690  }
6691  else
6692  {
6693  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6694  }
6695  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6696  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6697  if(!Manual)
6698  {
6699  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6700  }
6701  else
6702  {
6703  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6704  }
6705  }
6706  }
6707  else // at least one plain graphic
6708  {
6709  if(UpStep == 0)
6710  {
6711  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6712  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6713  if(!Manual)
6714  {
6715  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6716  }
6717  else
6718  {
6719  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6720  }
6721  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6722  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6723  if(!Manual)
6724  {
6725  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6726  }
6727  else
6728  {
6729  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6730  }
6731  }
6732  else if(DownStep == 0)
6733  {
6734  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6735  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6736  if(!Manual)
6737  {
6738  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6739  }
6740  else
6741  {
6742  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6743  }
6744  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6745  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6746  if(!Manual)
6747  {
6748  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6749  }
6750  else
6751  {
6752  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6753  }
6754  }
6755  else
6756  {
6757  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6758  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6759  if(!Manual)
6760  {
6761  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6762  }
6763  else
6764  {
6765  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6766  }
6767  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6768  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6769  if(!Manual)
6770  {
6771  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6772  }
6773  else
6774  {
6775  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6776  }
6777  }
6778  for(int x = (UpStep + 1); x < DownStep; x++)
6779  {
6780  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6781  if(x == 0)
6782  {
6783  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6784  }
6785  else
6786  {
6787  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6788  }
6789  if(!Manual)
6790  {
6791  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6792  }
6793  else
6794  {
6795  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6796  }
6797  }
6798  }
6799  Disp->Update();
6800  Utilities->CallLogPop(1958);
6801  return;
6802  }
6803 
6804  else // ver track element
6805  {
6806  // find leftmost LC, opening them all (to trains) in turn
6807  int LStep = 0;
6808  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6809  {
6810  LStep--;
6811  }
6812  LStep++;
6813  // now find rightmost LC, opening them all (to trains) in turn
6814  int RStep = 1;
6815  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6816  {
6817  RStep++;
6818  }
6819  RStep--;
6820  // now plot graphics, LStep is smallest & RStep largest
6821  Graphics::TBitmap *RouteGraphic;
6822  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6823  if(TypeOfRoute == 1)
6824  {
6825  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6826  }
6827  else if(TypeOfRoute == 0)
6828  {
6829  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6830  }
6831  else //manual
6832  {
6833  RouteGraphic = BaseGraphic;
6834  }
6835 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6836 // LinkSigRouteGraphicsPtr[1] ver }
6837 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6838 // LinkNonSigRouteGraphicsPtr[1] ver }
6839  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6840  {
6841  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6842  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6843  if(!Manual)
6844  {
6845  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6846  }
6847  else
6848  {
6849  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6850  }
6851  }
6852  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6853  {
6854  if(LStep == 0)
6855  {
6856  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6857  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6858  if(!Manual)
6859  {
6860  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6861  }
6862  else
6863  {
6864  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6865  }
6866  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6867  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6868  if(!Manual)
6869  {
6870  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6871  }
6872  else
6873  {
6874  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6875  }
6876  }
6877  else
6878  {
6879  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6880  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6881  if(!Manual)
6882  {
6883  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6884  }
6885  else
6886  {
6887  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6888  }
6889  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6890  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6891  if(!Manual)
6892  {
6893  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6894  }
6895  else
6896  {
6897  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6898  }
6899  }
6900  }
6901  else // at least one plain graphic
6902  {
6903  if(LStep == 0)
6904  {
6905  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6906  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6907  if(!Manual)
6908  {
6909  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6910  }
6911  else
6912  {
6913  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6914  }
6915  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6916  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6917  if(!Manual)
6918  {
6919  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6920  }
6921  else
6922  {
6923  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6924  }
6925  }
6926  else if(RStep == 0)
6927  {
6928  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6929  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6930  if(!Manual)
6931  {
6932  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6933  }
6934  else
6935  {
6936  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6937  }
6938  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6939  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6940  if(!Manual)
6941  {
6942  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6943  }
6944  else
6945  {
6946  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6947  }
6948  }
6949  else
6950  {
6951  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6952  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6953  if(!Manual)
6954  {
6955  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6956  }
6957  else
6958  {
6959  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6960  }
6961  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6962  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6963  if(!Manual)
6964  {
6965  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6966  }
6967  else
6968  {
6969  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6970  }
6971  }
6972  for(int x = (LStep + 1); x < RStep; x++)
6973  {
6974  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6975  if(x == 0)
6976  {
6977  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6978  }
6979  else
6980  {
6981  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6982  }
6983  if(!Manual)
6984  {
6985  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6986  }
6987  else
6988  {
6989  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6990  }
6991  }
6992  }
6993  Disp->Update();
6994  Utilities->CallLogPop(1896);
6995  return;
6996  }
6997 }
6998 
6999 // ---------------------------------------------------------------------------
7000 
7001 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7002 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7003 {
7004  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7005  AnsiString(HLoc) + "," + AnsiString(VLoc));
7006  if(!IsLCAtHV(29, HLoc, VLoc))
7007  {
7008  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7009  }
7010  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7011  {
7012  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7013  }
7014 // check for adjacent LCs & if so open (to trains)
7015  if(BaseElementSpeedTag == 1) // hor track element
7016  {
7017  // find topmost LC, opening them all (to trains) in turn
7018  int UpStep = 0;
7019  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7020  {
7021  UpStep--;
7022  }
7023  UpStep++;
7024  // now find bottommost LC, opening them all (to trains) in turn
7025  int DownStep = 1;
7026  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7027  {
7028  DownStep++;
7029  }
7030  DownStep--;
7031  // now plot graphics, UpStep is smallest & DownStep largest
7032  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7033  {
7034  if(!Manual)
7035  {
7036  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7037  }
7038  else
7039  {
7040  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7041  }
7042  }
7043  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7044  {
7045  if(!Manual)
7046  {
7047  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7048  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7049  }
7050  else
7051  {
7052  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7053  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7054  }
7055  }
7056  else // at least one plain graphic
7057  {
7058  if(!Manual)
7059  {
7060  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7061  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7062  for(int x = (UpStep + 1); x < DownStep; x++)
7063  {
7064  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7065  }
7066  }
7067  else
7068  {
7069  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7070  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7071  for(int x = (UpStep + 1); x < DownStep; x++)
7072  {
7073  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7074  }
7075  }
7076  }
7077  // set markers
7078  for(int x = UpStep; x <= DownStep; x++)
7079  {
7080  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7081  }
7082  Display->Update();
7083  Utilities->CallLogPop(1944);
7084  return;
7085  }
7086 
7087  else // ver track element
7088  {
7089  // find leftmost LC, opening them all (to trains) in turn
7090  int LStep = 0;
7091  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7092  {
7093  LStep--;
7094  }
7095  LStep++;
7096  // now find rightmost LC, opening them all (to trains) in turn
7097  int RStep = 1;
7098  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7099  {
7100  RStep++;
7101  }
7102  RStep--;
7103  // now plot graphics, LStep is smallest & RStep largest
7104  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7105  {
7106  if(!Manual)
7107  {
7108  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7109  }
7110  else
7111  {
7112  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7113  }
7114  }
7115  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7116  {
7117  if(!Manual)
7118  {
7119  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7120  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7121  }
7122  else
7123  {
7124  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7125  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7126  }
7127  }
7128  else // at least one plain graphic
7129  {
7130  if(!Manual)
7131  {
7132  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7133  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7134  for(int x = (LStep + 1); x < RStep; x++)
7135  {
7136  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7137  }
7138  }
7139  else
7140  {
7141  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7142  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7143  for(int x = (LStep + 1); x < RStep; x++)
7144  {
7145  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7146  }
7147  }
7148  }
7149  // set markers
7150  for(int x = LStep; x <= RStep; x++)
7151  {
7152  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7153  }
7154  Disp->Update();
7155  Utilities->CallLogPop(1945);
7156  return;
7157  }
7158 }
7159 
7160 // ---------------------------------------------------------------------------
7161 
7162 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7163 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7164 {
7165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7166  AnsiString(VLoc));
7167  if(!IsLCAtHV(9, HLoc, VLoc))
7168  {
7169  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7170  }
7171  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7172  {
7173  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7174  }
7175 // check for adjacent LCs & if so close (to trains)
7176  if(BaseElementSpeedTag == 1) // hor track element
7177  {
7178  // find topmost LC, closing them all (to trains) in turn
7179  int UpStep = 0;
7180  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7181  {
7182  UpStep--;
7183  }
7184  UpStep++;
7185  // now find bottommost LC, opening them all (to trains) in turn
7186  int DownStep = 1;
7187  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7188  {
7189  DownStep++;
7190  }
7191  DownStep--;
7192  // now plot graphics, UpStep is smallest & DownStep largest
7193  for(int x = UpStep; x < (DownStep + 1); x++)
7194  {
7195  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7196  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7197  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7198  }
7199  Disp->Update();
7200  Utilities->CallLogPop(1959);
7201  return;
7202  }
7203 
7204  else // ver track element
7205  {
7206  // find leftmost LC, closing them all (to trains) in turn
7207  int LStep = 0;
7208  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7209  {
7210  LStep--;
7211  }
7212  LStep++;
7213  // now find rightmost LC, opening them all (to trains) in turn
7214  int RStep = 1;
7215  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7216  {
7217  RStep++;
7218  }
7219  RStep--;
7220  // now plot graphics, LStep is smallest & RStep largest
7221  for(int x = LStep; x < (RStep + 1); x++)
7222  {
7223  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7224  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7225  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7226  }
7227  Disp->Update();
7228  Utilities->CallLogPop(1960);
7229  return;
7230  }
7231 }
7232 
7233 // ---------------------------------------------------------------------------
7234 
7235 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7236 // closed to trains
7237 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7238 {
7239  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7240  AnsiString(HLoc) + "," + AnsiString(VLoc));
7241  if(!IsLCAtHV(34, HLoc, VLoc))
7242  {
7243  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7244  }
7245  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7246  {
7247  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7248  }
7249  TTrackElement TE;
7250 
7251 // check for adjacent LCs & if so close (to trains)
7252  if(BaseElementSpeedTag == 1) // hor track element
7253  {
7254  // find topmost LC, closing them all (to trains) in turn
7255  int UpStep = 0;
7256  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7257  {
7258  UpStep--;
7259  }
7260  UpStep++;
7261  // now find bottommost LC, opening them all (to trains) in turn
7262  int DownStep = 1;
7263  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7264  {
7265  DownStep++;
7266  }
7267  DownStep--;
7268  // now plot graphics, UpStep is smallest & DownStep largest
7269  for(int x = UpStep; x <= DownStep; x++)
7270  {
7271  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7272  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7273  }
7274  Display->Update();
7275  Utilities->CallLogPop(1946);
7276  return;
7277  }
7278 
7279  else // ver track element
7280  {
7281  // find leftmost LC, closing them all (to trains) in turn
7282  int LStep = 0;
7283  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7284  {
7285  LStep--;
7286  }
7287  LStep++;
7288  // now find rightmost LC, opening them all (to trains) in turn
7289  int RStep = 1;
7290  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7291  {
7292  RStep++;
7293  }
7294  RStep--;
7295  // now plot graphics, LStep is smallest & RStep largest
7296  for(int x = LStep; x <= RStep; x++)
7297  {
7298  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7299  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7300  }
7301  Display->Update();
7302  Utilities->CallLogPop(1947);
7303  return;
7304  }
7305 }
7306 
7307 // ---------------------------------------------------------------------------
7308 
7309 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7310 {
7311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7312  Graphics::TBitmap *RouteGraphic;
7313  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7314 
7315  if(BaseElementSpeedTag == 1)
7316  {
7317  if(TypeOfRoute == 1)
7318  {
7319  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7320  }
7321  else if(TypeOfRoute == 0)
7322  {
7323  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7324  }
7325  else //manual
7326  {
7327  RouteGraphic = BaseGraphic;
7328  }
7329  if(State == Raising)
7330  {
7331  RouteGraphic = BaseGraphic;
7332  }
7333  }
7334  else
7335  {
7336  BaseGraphic = RailGraphics->gl2;
7337  if(TypeOfRoute == 1)
7338  {
7339  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7340  }
7341  else if(TypeOfRoute == 0)
7342  {
7343  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7344  }
7345  else
7346  {
7347  RouteGraphic = BaseGraphic; //manual
7348  }
7349  if(State == Raising)
7350  {
7351  RouteGraphic = BaseGraphic;
7352  }
7353  }
7354  int UpStep = 0;
7355 
7356  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7357  {
7358  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7359  if(UpStep == 0)
7360  {
7361  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7362  }
7363  else
7364  {
7365  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7366  }
7367  UpStep--;
7368  }
7369 // now find bottommost LC, opening them all (to trains) in turn
7370  int DownStep = 1;
7371 
7372  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7373  {
7374  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7375  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7376  DownStep++;
7377  }
7378  int LeftStep = 0;
7379 
7380  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7381  {
7382  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7383  if(LeftStep == 0)
7384  {
7385  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7386  }
7387  else
7388  {
7389  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7390  }
7391  LeftStep--;
7392  }
7393 // now find rightmost LC, opening them all (to trains) in turn
7394  int RightStep = 1;
7395 
7396  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7397  {
7398  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7399  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7400  RightStep++;
7401  }
7402  Disp->Update();
7403  Utilities->CallLogPop(1914);
7404 }
7405 
7406 // ---------------------------------------------------------------------------
7407 
7408 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7409 {
7410 // return false for no LC there, flashing or a closed (to trains) LC
7411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7412  bool FoundFlag;
7413  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7414 
7415  if(!FoundFlag)
7416  {
7417  Utilities->CallLogPop(1898);
7418  return(false);
7419  }
7420  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7421  {
7422  Utilities->CallLogPop(1899);
7423  return(false);
7424  }
7425  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7426  {
7427  Utilities->CallLogPop(1900);
7428  return(true);
7429  }
7430  Utilities->CallLogPop(1901);
7431  return(false);
7432 }
7433 
7434 // ---------------------------------------------------------------------------
7435 
7436 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7437 {
7438 // return false for no LC there, flashing LC or open (to trains) LC
7439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7440  bool FoundFlag;
7441  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7442 
7443  if(!FoundFlag)
7444  {
7445  Utilities->CallLogPop(1922);
7446  return(false);
7447  }
7448  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7449  {
7450  Utilities->CallLogPop(1923);
7451  return(false);
7452  }
7453  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7454  {
7455  Utilities->CallLogPop(1924);
7456  return(true);
7457  }
7458  Utilities->CallLogPop(1925);
7459  return(false);
7460 }
7461 
7462 // ---------------------------------------------------------------------------
7463 
7464 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7465 {
7466 // return true for barrier in process of moving
7467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7468  bool FoundFlag;
7469  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7470 
7471  if(!FoundFlag)
7472  {
7473  Utilities->CallLogPop(1918);
7474  return(false);
7475  }
7476  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7477  {
7478  Utilities->CallLogPop(1919);
7479  return(false);
7480  }
7481  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7482  {
7483  Utilities->CallLogPop(1920);
7484  return(true);
7485  }
7486  Utilities->CallLogPop(1921);
7487  return(false);
7488 }
7489 
7490 // ---------------------------------------------------------------------------
7491 
7492 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7493 {
7494 // return true for an LC at H&V
7495  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7496  bool FoundFlag;
7497  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7498 
7499  if(!FoundFlag)
7500  {
7501  Utilities->CallLogPop(1902);
7502  return(false);
7503  }
7504  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7505  {
7506  Utilities->CallLogPop(1903);
7507  return(false);
7508  }
7509  Utilities->CallLogPop(1904);
7510  return(true);
7511 }
7512 
7513 // ---------------------------------------------------------------------------
7514 
7515 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7516 {
7517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7518  AnsiString(Attr));
7519  bool FoundFlag;
7520  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7521 
7522  if(!FoundFlag)
7523  {
7524  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7525  }
7526  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7527  {
7528  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7529  }
7530  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7531  Utilities->CallLogPop(1905);
7532  return;
7533 }
7534 
7535 // ---------------------------------------------------------------------------
7536 
7538 {
7539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7540  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7541  {
7542  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7543  if(InactiveTrackElement.TrackType == LevelCrossing)
7544  {
7545  InactiveTrackElementAt(141, x).Attribute = 0;
7546  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7547  }
7548  }
7549  Utilities->CallLogPop(1913);
7550  return;
7551 }
7552 
7553 // ---------------------------------------------------------------------------
7554 
7555 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7556 {
7557 // return true if there is either a route set or being set on any element or a train on any element
7558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7559  "," + AnsiString(VLoc));
7560 
7561  THVPair TrackMapKeyPair;
7562  TTrack::TTrackMapIterator TrackMapPtr;
7563  int DummyRouteNumber;
7564 
7565  TrainPresent = false;
7566 // find topmost LC, checking each for routes & trains
7567  int UpStep = 0;
7568 
7569  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7570  {
7571  TrackMapKeyPair.first = HLoc;
7572  TrackMapKeyPair.second = VLoc + UpStep;
7573  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7574  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7575  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7576  {
7577  Utilities->CallLogPop(1932);
7578  return(true);
7579  }
7580  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7581  {
7582  TrainPresent = true;
7583  Utilities->CallLogPop(1933);
7584  return(true);
7585  }
7586  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7587  {
7588  Utilities->CallLogPop(2274);
7589  return(true);
7590  }
7591  UpStep--;
7592  }
7593 // now find bottommost LC, opening them all (to trains) in turn
7594  int DownStep = 1;
7595 
7596  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7597  {
7598  TrackMapKeyPair.first = HLoc;
7599  TrackMapKeyPair.second = VLoc + DownStep;
7600  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7601  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7602  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7603  {
7604  Utilities->CallLogPop(1934);
7605  return(true);
7606  }
7607  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7608  {
7609  TrainPresent = true;
7610  Utilities->CallLogPop(1935);
7611  return(true);
7612  }
7613  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7614  {
7615  Utilities->CallLogPop(2275);
7616  return(true);
7617  }
7618  DownStep++;
7619  }
7620 // find leftmost LC
7621  int LeftStep = 0;
7622 
7623  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7624  {
7625  TrackMapKeyPair.first = HLoc + LeftStep;
7626  TrackMapKeyPair.second = VLoc;
7627  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7628  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7629  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7630  {
7631  Utilities->CallLogPop(1936);
7632  return(true);
7633  }
7634  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7635  {
7636  TrainPresent = true;
7637  Utilities->CallLogPop(1937);
7638  return(true);
7639  }
7640  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7641  {
7642  Utilities->CallLogPop(2276);
7643  return(true);
7644  }
7645  LeftStep--;
7646  }
7647 // now find rightmost LC, opening them all (to trains) in turn
7648  int RightStep = 1;
7649 
7650  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7651  {
7652  TrackMapKeyPair.first = HLoc + RightStep;
7653  TrackMapKeyPair.second = VLoc;
7654  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7655  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7656  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7657  {
7658  Utilities->CallLogPop(1938);
7659  return(true);
7660  }
7661  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7662  {
7663  TrainPresent = true;
7664  Utilities->CallLogPop(1939);
7665  return(true);
7666  }
7667  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7668  {
7669  Utilities->CallLogPop(2277);
7670  return(true);
7671  }
7672  RightStep++;
7673  }
7674  Utilities->CallLogPop(1940);
7675  return(false);
7676 }
7677 
7678 // ---------------------------------------------------------------------------
7679 
7680 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7681 {
7682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7683  for(unsigned int x = 0; x < SearchVector.size(); x++)
7684  {
7685  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7686  {
7687  Utilities->CallLogPop(2278);
7688  return(true);
7689  }
7690  }
7691  Utilities->CallLogPop(2279);
7692  return(false);
7693 }
7694 
7695 // ---------------------------------------------------------------------------
7696 
7697 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7698 {
7699  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7700  AnsiString(HLoc) + "," + AnsiString(VLoc));
7701  if(!IsLCAtHV(60, HLoc, VLoc))
7702  {
7703  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7704  }
7705 
7706 // check for adjacent LCs
7707  // find topmost LC
7708  int UpStep = 0;
7709  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7710  {
7711  UpStep--;
7712  }
7713  UpStep++;
7714  // now find bottommost LC, opening them all (to trains) in turn
7715  int DownStep = 1;
7716  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7717  {
7718  DownStep++;
7719  }
7720  DownStep--;
7721  // now plot graphics, UpStep is smallest & DownStep largest
7722  for(int x = UpStep; x <= DownStep; x++)
7723  {
7724  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7725  }
7726 
7727  // find leftmost LC, closing them all (to trains) in turn
7728  int LStep = 0;
7729  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7730  {
7731  LStep--;
7732  }
7733  LStep++;
7734  // now find rightmost LC, opening them all (to trains) in turn
7735  int RStep = 1;
7736  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7737  {
7738  RStep++;
7739  }
7740  RStep--;
7741  // now plot graphics, LStep is smallest & RStep largest
7742  for(int x = LStep; x <= RStep; x++)
7743  {
7744  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7745  }
7746  Display->Update();
7747  Utilities->CallLogPop(2315);
7748  return;
7749 }
7750 
7751 // ---------------------------------------------------------------------------
7752 
7753 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7754 {
7755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7756  if(TrackElement.TrackType != Points)
7757  {
7758  throw Exception("Error, Wrong track type in GetFilletGraphic");
7759  }
7760  if(TrackElement.SpeedTag < 28)
7761  {
7762  Utilities->CallLogPop(521);
7763  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7764  }
7765  else if(TrackElement.SpeedTag < 132)
7766  {
7767  Utilities->CallLogPop(522);
7768 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7769  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7770  }
7771  else
7772  {
7773  Utilities->CallLogPop(1537);
7774  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7775  }
7776 }
7777 
7778 // ---------------------------------------------------------------------------
7779 
7781 {
7782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7783  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7784  {
7785  TrackElementAt(1351, x).TrainIDOnElement = -1;
7788  }
7789  Utilities->CallLogPop(1342);
7790 }
7791 
7792 // ---------------------------------------------------------------------------
7793 
7794 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7795 /*
7796  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7797 */
7798 {
7799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7800  AnsiString(ScreenPosV));
7801  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7802  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7803 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7804  Utilities->CallLogPop(535);
7805 }
7806 
7807 // ---------------------------------------------------------------------------
7808 
7809 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7810 /*
7811  Converts the screen position to the true (without offsets) position
7812 */
7813 {
7814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7815  AnsiString(ScreenPosV));
7816  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7817  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7818  Utilities->CallLogPop(536);
7819 }
7820 
7821 // ---------------------------------------------------------------------------
7822 
7823 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7824 {
7825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7826  AnsiString(VPosTrue));
7827  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7828  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7829  Utilities->CallLogPop(537);
7830 }
7831 
7832 // ---------------------------------------------------------------------------
7833 
7834 void TTrack::CheckMapAndTrack(int Caller) // test
7835 {
7836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7837  int Zeroes = 0;
7838  bool FoundFlag;
7839 
7840  for(unsigned int a = 0; a < TrackVector.size(); a++)
7841  {
7842  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7843  if(CheckElement.SpeedTag == 0)
7844  {
7845  Zeroes++; // zeroed elements not saved in map
7846  }
7847  else
7848  {
7849  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7850  if(!FoundFlag)
7851  {
7852  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7853  " in TrackMap, Caller=" + (AnsiString)Caller);
7854  }
7855  if(MapVecPos != (int)a)
7856  {
7857  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7858  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7859  (AnsiString)Caller);
7860  }
7861  }
7862  }
7863  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7864  {
7865  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7866  " Caller=" + (AnsiString)Caller);
7867  }
7868  Utilities->CallLogPop(538);
7869  return;
7870 }
7871 
7872 // ---------------------------------------------------------------------------
7873 
7874 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7875 {
7876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7877  bool FoundFlag;
7878  TIMPair InactivePair;
7879 
7880  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7881  {
7882  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7883  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7884  if(!FoundFlag)
7885  {
7886  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7887  " in InactiveMap, Caller=" + (AnsiString)Caller);
7888  }
7889  if((InactivePair.first != a) && (InactivePair.second != a))
7890  {
7891  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7892  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7893  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7894  }
7895  }
7896  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7897  {
7898  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7899  " Caller=" + (AnsiString)Caller);
7900  }
7901  Utilities->CallLogPop(539);
7902 }
7903 
7904 // ---------------------------------------------------------------------------
7905 
7906 void TTrack::CheckGapMap(int Caller) // test
7907 {
7908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7909  int Position1, Position2;
7910  TTrackElement TrackElement1, TrackElement2;
7911  TGapMapIterator GapMapPtr;
7912 
7913  if(!GapMap.empty())
7914  {
7915  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7916  {
7917  int HLoc1 = GapMapPtr->first.first;
7918  int VLoc1 = GapMapPtr->first.second;
7919  int HLoc2 = GapMapPtr->second.first;
7920  int VLoc2 = GapMapPtr->second.second;
7921  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7922  {
7923  throw Exception("Failed to find H & V for gap1, GapMap in error");
7924  }
7925  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7926  {
7927  throw Exception("Failed to find H & V for gap2, GapMap in error");
7928  }
7929  if(TrackElementAt(17, Position1).TrackType != GapJump)
7930  {
7931  throw Exception("Element at Pos1 not a gap, GapMap in error");
7932  }
7933  if(TrackElementAt(18, Position2).TrackType != GapJump)
7934  {
7935  throw Exception("Element at Pos2 not a gap, GapMap in error");
7936  }
7937  }
7938  }
7939  unsigned int GapCount = 0;
7940 
7941  for(unsigned int a = 0; a < TrackVector.size(); a++)
7942  {
7943  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7944  if(CheckElement.TrackType == GapJump)
7945  {
7946  GapCount++;
7947  }
7948  }
7949  if((GapMap.size() * 2) != GapCount)
7950  {
7951  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7952  (AnsiString)Caller);
7953  }
7954  Utilities->CallLogPop(540);
7955 }
7956 
7957 // ---------------------------------------------------------------------------
7958 
7959 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7960 {
7961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7962  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7963  {
7964  if(TrackFinished)
7965  {
7966  throw Exception("Error - TrackFinished with erase element still present");
7967  }
7968  Utilities->CallLogPop(541);
7969  return; // erased element, can't set ID
7970  }
7971  AnsiString IDString;
7972 
7973  if(TrackElement.HLoc < 0)
7974  {
7975  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7976  }
7977  else
7978  {
7979  IDString = AnsiString(TrackElement.HLoc) + "-";
7980  }
7981  if(TrackElement.VLoc < 0)
7982  {
7983  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7984  }
7985  else
7986  {
7987  IDString += AnsiString(TrackElement.VLoc);
7988  }
7989  TrackElement.ElementID = IDString;
7990  Utilities->CallLogPop(542);
7991 }
7992 
7993 // ---------------------------------------------------------------------------
7994 
7995 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7996 {
7997 // e.g. "8-13", "00008-13", "N43-N127", etc
7998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
7999  int DelimPos;
8000 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8001  {
8002  for(int x = 1; x < String.Length() + 1; x++)
8003  {
8004  if(String.IsDelimiter("-", x))
8005  {
8006  DelimPos = x;
8007  break;
8008  }
8009  if(x == String.Length())
8010  {
8011  if(GiveMessages)
8012  {
8013  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8014  }
8015  Utilities->CallLogPop(543);
8016  return(-1);
8017  }
8018  }
8019  if(DelimPos == 1)
8020  {
8021  if(GiveMessages)
8022  {
8023  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8024  }
8025  Utilities->CallLogPop(544);
8026  return(-1);
8027  }
8028  if(DelimPos == String.Length())
8029  {
8030  if(GiveMessages)
8031  {
8032  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8033  }
8034  Utilities->CallLogPop(545);
8035  return(-1);
8036  }
8037  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8038  {
8039  if(GiveMessages)
8040  {
8041  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8042  }
8043  Utilities->CallLogPop(1508);
8044  return(-1);
8045  }
8046  int HLoc, VLoc;
8047 
8048  if(String.SubString(1, 1) != "N")
8049  {
8050  for(int x = 1; x < DelimPos; x++)
8051  {
8052  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8053  {
8054  if(GiveMessages)
8055  {
8056  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8057  }
8058  Utilities->CallLogPop(546);
8059  return(-1);
8060  }
8061  }
8062  }
8063  if(String.SubString(1, 1) == "N")
8064  {
8065  for(int x = 2; x < DelimPos; x++)
8066  {
8067  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8068  {
8069  if(GiveMessages)
8070  {
8071  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8072  }
8073  Utilities->CallLogPop(763);
8074  return(-1);
8075  }
8076  }
8077  }
8078  if(String.SubString(1, 1) == "N")
8079  {
8080  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8081  }
8082  else
8083  {
8084  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8085  }
8086  if(String.SubString(DelimPos + 1, 1) != "N")
8087  {
8088  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8089  {
8090  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8091  {
8092  if(GiveMessages)
8093  {
8094  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8095  }
8096  Utilities->CallLogPop(547);
8097  return(-1);
8098  }
8099  }
8100  }
8101  if(String.SubString(DelimPos + 1, 1) == "N")
8102  {
8103  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8104  {
8105  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8106  {
8107  if(GiveMessages)
8108  {
8109  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8110  }
8111  Utilities->CallLogPop(764);
8112  return(-1);
8113  }
8114  }
8115  }
8116  if(String.SubString(DelimPos + 1, 1) == "N")
8117  {
8118  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8119  }
8120  else
8121  {
8122  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8123  }
8124  THVPair HVPair(HLoc, VLoc);
8125  TTrackMapIterator TrackMapPtr;
8126 
8127  TrackMapPtr = TrackMap.find(HVPair);
8128  if(TrackMapPtr == TrackMap.end())
8129  {
8130  if(GiveMessages)
8131  {
8132  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8133  }
8134  Utilities->CallLogPop(548);
8135  return(-1);
8136  }
8137  Utilities->CallLogPop(549);
8138  return(TrackMapPtr->second);
8139  }
8140  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8141  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8142  {
8143  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8144  Utilities->CallLogPop(2481);
8145  return(-1);
8146  }
8147 }
8148 
8149 // ---------------------------------------------------------------------------
8150 
8151 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8152 /*
8153  True for linked properly at both ends
8154 */
8155 {
8156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8157  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8158  int HLoc = TrackElement.HLoc;
8159  int VLoc = TrackElement.VLoc;
8160 
8161  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8162  {
8163  Utilities->CallLogPop(1821);
8164  return(false);
8165  }
8166  if(TrackElement.SpeedTag == 129) // vertical footbridge
8167  {
8168  // check top connection
8169  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8170  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8171  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8172  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8173  {
8174  Utilities->CallLogPop(550);
8175  return(false);
8176  }
8177  // check bottom connection
8178  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8179  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8180  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8181  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8182  {
8183  Utilities->CallLogPop(551);
8184  return(false);
8185  }
8186  }
8187  if(TrackElement.SpeedTag == 145) // vertical underpass
8188  {
8189  // check top connection
8190  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8191  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8192  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8193  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8194  {
8195  Utilities->CallLogPop(2114);
8196  return(false);
8197  }
8198  // check bottom connection
8199  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8200  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8201  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8202  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8203  {
8204  Utilities->CallLogPop(2115);
8205  return(false);
8206  }
8207  }
8208  if(TrackElement.SpeedTag == 130) // hor footbridge
8209  {
8210  // check left connection
8211  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8212  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8213  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8214  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8215  {
8216  Utilities->CallLogPop(552);
8217  return(false);
8218  }
8219  // check right connection
8220  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8221  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8222  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8223  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8224  {
8225  Utilities->CallLogPop(553);
8226  return(false);
8227  }
8228  }
8229  if(TrackElement.SpeedTag == 146) // hor u'pass
8230  {
8231  // check left connection
8232  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8233  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8234  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8235  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8236  {
8237  Utilities->CallLogPop(2116);
8238  return(false);
8239  }
8240  // check right connection
8241  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8242  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8243  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8244  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8245  {
8246  Utilities->CallLogPop(2117);
8247  return(false);
8248  }
8249  }
8250  Utilities->CallLogPop(554);
8251  return(true);
8252 }
8253 
8254 // ---------------------------------------------------------------------------
8255 
8256 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8257 /*
8258  return true if the SpeedTag present in the map at H & V
8259 */
8260 {
8261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8262  AnsiString(SpeedTag));
8263  if(InactiveTrack2MultiMap.empty())
8264  {
8265  Utilities->CallLogPop(555);
8266  return(false);
8267  }
8268  THVPair HVPair(HLoc, VLoc);
8270  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8271  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8272 
8273  if(HVRange.first == HVRange.second)
8274  {
8275  Utilities->CallLogPop(556);
8276  return(false);
8277  }
8278  else
8279  {
8280  HVIt1 = HVRange.first;
8281  }
8282  TTrackElement Temp1, Temp2; // test
8283 
8284  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8285  if(--HVRange.second != HVRange.first)
8286  {
8287  HVIt2 = HVRange.second;
8288  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8289  }
8290  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8291  HVIt2->second).SpeedTag == SpeedTag)))
8292  {
8293  Utilities->CallLogPop(557);
8294  return(true);
8295  }
8296  else
8297  {
8298  Utilities->CallLogPop(558);
8299  return(false);
8300  }
8301 }
8302 
8303 // ---------------------------------------------------------------------------
8304 
8305 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8306 /*
8307  return true if the SpeedTag present in the map at H & V
8308 */
8309 {
8310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8311  AnsiString(SpeedTag));
8312  if(TrackMap.empty())
8313  {
8314  Utilities->CallLogPop(559);
8315  return(false);
8316  }
8317  THVPair HVPair(HLoc, VLoc);
8318  TTrackMapIterator End = TrackMap.end();
8319  TTrackMapIterator It = End;
8320 
8321  It = TrackMap.find(HVPair);
8322  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8323  {
8324  Utilities->CallLogPop(560);
8325  return(true);
8326  }
8327  else
8328  {
8329  Utilities->CallLogPop(561);
8330  return(false);
8331  }
8332 }
8333 
8334 // ---------------------------------------------------------------------------
8335 
8336 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8337 {
8338 /*
8339  General:
8340  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8341  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8342  a NamedNonStationLocation.
8343  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8344  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8345  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8346  platform at that location).
8347 
8348  Linked named location elements are those explained in TTrack::TTrack()
8349 
8350  Detail:
8351  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8352  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8353  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8354  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8355  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8356  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8357 
8358  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8359  this function a single element should be in the List (normally from the user's selection but can also be from
8360  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8361  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8362  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8363  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8364  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8365  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8366  moves them into the Map. At the end all linked elements are in the Map.
8367 
8368  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8369  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8370  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8371 */
8372 
8373 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8374 // Display->FileDiagnostics(TestString);//test
8375 
8376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8377  AnsiString TestString1, TestString2; // test
8378 
8379  Track->LNDone2MultiMap.clear();
8380  if(LNPendingList.size() != 1)
8381  {
8382  throw Exception("LNPendingList size not 1 on entry");
8383  }
8384  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8385  while(!LNPendingList.empty())
8386  {
8387  CurrentElementNumber = LNPendingList.front();
8388  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8389  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8390  int H = CurrentElement->HLoc;
8391  int V = CurrentElement->VLoc;
8392  int Tag = CurrentElement->SpeedTag;
8393  if(Tag == 76) // top plat
8394  {
8395  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8396  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8397  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8398  for(int x = 0; x < 25; x++)
8399  {
8400  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8401  {
8402  LNPendingList.insert(LNPendingList.end(), NewElement);
8403  }
8404  }
8405  }
8406  else if(Tag == 77) // bot plat
8407  {
8408  for(int x = 0; x < 25; x++)
8409  {
8410  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8411  {
8412  LNPendingList.insert(LNPendingList.end(), NewElement);
8413  }
8414  }
8415  }
8416  else if(Tag == 78) // l plat
8417  {
8418  for(int x = 0; x < 25; x++)
8419  {
8420  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8421  {
8422  LNPendingList.insert(LNPendingList.end(), NewElement);
8423  }
8424  }
8425  }
8426  else if(Tag == 79) // r plat
8427  {
8428  for(int x = 0; x < 25; x++)
8429  {
8430  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8431  {
8432  LNPendingList.insert(LNPendingList.end(), NewElement);
8433  }
8434  }
8435  }
8436  else if(Tag == 96) // conc
8437  {
8438  for(int x = 0; x < 28; x++)
8439  {
8440  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8441  {
8442  LNPendingList.insert(LNPendingList.end(), NewElement);
8443  }
8444  }
8445  }
8446  else if(Tag == 129) // vert footbridge
8447  {
8448  for(int x = 0; x < 8; x++)
8449  {
8450  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8451  {
8452  LNPendingList.insert(LNPendingList.end(), NewElement);
8453  }
8454  }
8455  }
8456  else if(Tag == 130) // hor footbridge
8457  {
8458  for(int x = 0; x < 8; x++)
8459  {
8460  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8461  {
8462  LNPendingList.insert(LNPendingList.end(), NewElement);
8463  }
8464  }
8465  }
8466  else if(Tag == 131) // named location
8467  {
8468  for(int x = 0; x < 4; x++)
8469  {
8470  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8471  {
8472  LNPendingList.insert(LNPendingList.end(), NewElement);
8473  }
8474  }
8475  }
8476  else if(Tag == 145) // v u'pass
8477  {
8478  for(int x = 0; x < 8; x++)
8479  {
8480  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8481  {
8482  LNPendingList.insert(LNPendingList.end(), NewElement);
8483  }
8484  }
8485  }
8486  else if(Tag == 146) // h u'pass
8487  {
8488  for(int x = 0; x < 8; x++)
8489  {
8490  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8491  {
8492  LNPendingList.insert(LNPendingList.end(), NewElement);
8493  }
8494  }
8495  }
8496  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8497 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8498  if(AddingElements)
8499  {
8500  int HPos, VPos; // not used but needed for FindText function
8501  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8502  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8503  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8504  {
8505  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8506  if((ExistingName != "") && (ExistingName != LocationName))
8507  {
8508  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8509  {
8510  } // name not in LocationNameMultiMap, so don't erase from TextVector
8511  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8512  {
8513  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8514  {
8515  ;
8516  } // condition not used
8517 
8518  }
8519  }
8520  }
8521  }
8522  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8523  // track at that loc
8524  THVPair HVPair(H, V);
8525  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8526  LNDone2MultiMapEntry.first = HVPair;
8527  LNDone2MultiMapEntry.second = LNPendingList.front();
8528  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8529  LNPendingList.erase(LNPendingList.begin());
8530  }
8531 
8532 // search all name multimap for same name where corresponding active elements don't appear in
8533 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8534 
8535  TLocationNameMultiMapIterator SNIterator;
8536  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8537  bool FoundFlag, ErasedFlag = false;
8538 
8539  if(SNRange.first != SNRange.second)
8540  {
8541  SNRange.first--; // now pointing to before the first
8542  SNRange.second--; // now pointing to the last
8543  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8544  {
8545  // Same elements are in Done map as in name map
8546  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8547  {
8548  ErasedFlag = true;
8549  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8550  TVIt->LocationName = "";
8551  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8552  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8553  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8554  {
8555  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8556  if(FoundFlag)
8557  {
8558  TrackElementAt(20, Position).LocationName = "";
8559  TrackElementAt(21, Position).ActiveTrackElementName = "";
8560  }
8561  }
8562  // erase name in name map
8563 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8564  }
8565  }
8566  }
8567  if(ErasedFlag)
8568  {
8570  }
8571  if(TrackFinished)
8572  {
8574  }
8575 // set here as well as in LinkTrack so don't have to link track just because a name added
8576 // if track not finished then will be set when track validated
8577 
8578 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8579 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8580 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8581 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8582 // so the error would be seen.
8583 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8584  std::pair<AnsiString, char>TempMapPair;
8585 
8586  ContinuationNameMap.clear();
8587  for(int x = 0; x < Track->TrackVectorSize(); x++)
8588  {
8589  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8590  {
8591  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8592  TempMapPair.second = 'x'; // unused
8593  ContinuationNameMap.insert(TempMapPair);
8594  }
8595  }
8596 //end of addition
8597  CheckLocationNameMultiMap(1); // test
8598  Utilities->CallLogPop(562);
8599 }
8600 
8601 // ---------------------------------------------------------------------------
8602 
8603 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8604 /*
8605  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8606  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8607 */
8608 {
8609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8610  AnsiString(SpeedTag));
8611  if(!NamedLocationElementAt(2, HLoc, VLoc))
8612  {
8613  Utilities->CallLogPop(948);
8614  return(false);
8615  }
8616  bool FoundFlag;
8617  int Position = -1;
8618  TIMPair IMPair;
8619 
8620  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8621  {
8622  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8623  if(FoundFlag)
8624  {
8625  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8626  {
8627  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8628  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8629  // don't allow duplicates in either list, or processing takes a lot longer
8630  {
8631  FoundElement = MapPos;
8632  Utilities->CallLogPop(563);
8633  return(true);
8634  }
8635  }
8636  }
8637  }
8638  else
8639  {
8640  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8641  if(FoundFlag)
8642  {
8643  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8644  {
8645  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8646  {
8647  FoundElement = IMPair.first;
8648  Utilities->CallLogPop(564);
8649  return(true);
8650  }
8651  }
8652  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8653  {
8654  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8655  {
8656  FoundElement = IMPair.second;
8657  Utilities->CallLogPop(565);
8658  return(true);
8659  }
8660  }
8661  }
8662  }
8663  Utilities->CallLogPop(566);
8664  return(false);
8665 }
8666 
8667 // ---------------------------------------------------------------------------
8668 
8669 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8670 /*
8671  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8672  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8673  with the new name
8674 */
8675 {
8676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8677  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8678 
8679  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8680  int HLoc = TrackElement->HLoc;
8681  int VLoc = TrackElement->VLoc;
8682  bool FoundFlag;
8683 
8684  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8685  // only have timetable names for adjacent platforms & named locations
8686  {
8687  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8688  if(FoundFlag)
8689  {
8690  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8691  }
8692  }
8693  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8694 
8695  if(ErrorString != "")
8696  {
8697  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8698  }
8699  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8700  CheckLocationNameMultiMap(2); // test
8701  Utilities->CallLogPop(567);
8702 }
8703 
8704 // ---------------------------------------------------------------------------
8705 
8706 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8707 /*
8708  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8709 */
8710 {
8711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8712  if(LNDone2MultiMap.empty())
8713  {
8714  Utilities->CallLogPop(568);
8715  return(false);
8716  }
8717  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8718 
8719  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8720  {
8721  if(LNDone2MultiMapIterator->second == MapPos)
8722  {
8723  Utilities->CallLogPop(569);
8724  return(true);
8725  }
8726  }
8727  Utilities->CallLogPop(570);
8728  return(false);
8729 }
8730 
8731 // ---------------------------------------------------------------------------
8732 
8733 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8734 /*
8735  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8736 */
8737 {
8738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8739  if(LNPendingList.empty())
8740  {
8741  Utilities->CallLogPop(571);
8742  return(false);
8743  }
8744  TLNPendingListIterator LNPendingListIterator;
8745 
8746  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8747  {
8748  if(*LNPendingListIterator == MapPos)
8749  {
8750  Utilities->CallLogPop(572);
8751  return(true);
8752  }
8753  }
8754  Utilities->CallLogPop(573);
8755  return(false);
8756 }
8757 
8758 // ---------------------------------------------------------------------------
8759 
8760 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8761 /*
8762  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8763 */
8764 {
8765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8766  THVPair HVPair(HLoc, VLoc);
8767  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8768  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8769 
8770  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8771  {
8772  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8773  {
8774  Utilities->CallLogPop(574);
8775  return(true);
8776  }
8777  }
8778  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8779  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8780  {
8781  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8782  {
8783  Utilities->CallLogPop(575);
8784  return(true);
8785  }
8786  }
8787  Utilities->CallLogPop(576);
8788  return(false);
8789 }
8790 
8791 // ---------------------------------------------------------------------------
8792 
8793 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8794 {
8795  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8796  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8797  {
8798  Utilities->CallLogPop(1953);
8799  return(true);
8800  }
8801  Utilities->CallLogPop(1954);
8802  return(false);
8803 }
8804 
8805 // ---------------------------------------------------------------------------
8806 
8807 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8808 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8809 //program and used when try to save as a .rly file
8810 {
8811  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8814  if(LocationNameMultiMap.empty()) //no names so no duplicates
8815  {
8816  Utilities->CallLogPop(2254);
8817  return(false);
8818  }
8819  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8820  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8821  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8822  {
8824  {
8825  if(GiveMessage)
8826  {
8827  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8828  }
8829  Utilities->CallLogPop(2255);
8830  return(true);
8831  }
8832  }
8833  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8834  {
8835  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8836  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8837  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8838  {
8840  {
8841  if(GiveMessage)
8842  {
8843  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8844  }
8845  Utilities->CallLogPop(2256);
8846  return(true);
8847  }
8848  }
8849  }
8850  Utilities->CallLogPop(2257);
8851  return(false); //OK, no duplicates
8852 }
8853 
8854 // ---------------------------------------------------------------------------
8855 
8857 {
8858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8859  THVPair HVPair;
8860  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8861  //for use in the duplicate check
8862  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8863  {
8864  if(LNMMIt->second < 0) //active track element
8865  {
8866  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8867  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8868  }
8869  else //inactive track element
8870  {
8871  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8872  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8873  }
8874  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8875  }
8876  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8877 
8878  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8879  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8880  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8881 
8882  std::list<THVPair> HVLinkedList;
8883 
8884  //set the first value to true and add it to the list
8885  HVPairsLinkedMap.begin()->second = true;
8886  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8887  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8888  //examination
8889  THVPair HVPairUnderExamination;
8890  THVPairsLinkedMap::iterator HVPLMIt;
8891  THVPair HVPairNew;
8892  while(!HVLinkedList.empty())
8893  {
8894  HVPairUnderExamination = HVLinkedList.front();
8895  HVLinkedList.pop_front();
8896  HVPairNew.first = HVPairUnderExamination.first;
8897  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8898  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8899  if(HVPLMIt != HVPairsLinkedMap.end())
8900  {
8901  if(!HVPLMIt->second)
8902  {
8903  HVLinkedList.push_back(HVPLMIt->first);
8904  }
8905  HVPLMIt->second = true;
8906  }
8907  HVPairNew.first = HVPairUnderExamination.first - 1;
8908  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8909  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8910  if(HVPLMIt != HVPairsLinkedMap.end())
8911  {
8912  if(!HVPLMIt->second)
8913  {
8914  HVLinkedList.push_back(HVPLMIt->first);
8915  }
8916  HVPLMIt->second = true;
8917  }
8918  HVPairNew.first = HVPairUnderExamination.first;
8919  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8920  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8921  if(HVPLMIt != HVPairsLinkedMap.end())
8922  {
8923  if(!HVPLMIt->second)
8924  {
8925  HVLinkedList.push_back(HVPLMIt->first);
8926  }
8927  HVPLMIt->second = true;
8928  }
8929  HVPairNew.first = HVPairUnderExamination.first + 1;
8930  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8931  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8932  if(HVPLMIt != HVPairsLinkedMap.end())
8933  {
8934  if(!HVPLMIt->second)
8935  {
8936  HVLinkedList.push_back(HVPLMIt->first);
8937  }
8938  HVPLMIt->second = true;
8939  }
8940  }
8941 
8942  //at the end if any have a false bool then the name is duplicated so return false
8943  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8944  {
8945  if(!HVPLMIt->second)
8946  {
8947  Utilities->CallLogPop(2258);
8948  return(false);
8949  }
8950  }
8951  Utilities->CallLogPop(2259);
8952  return(true);
8953 }
8954 
8955 // ---------------------------------------------------------------------------
8956 
8957 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8958 /*
8959  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8960 */
8961 
8962 {
8963  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8964  if(LocationName == "")
8965  {
8966  Utilities->CallLogPop(577);
8967  return(false);
8968  }
8969 // new for v0.2b
8970 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8972  {
8973  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8974  ActiveTrackElementNameMap.clear();
8975  for(unsigned int x = 0; x < TrackVector.size(); x++)
8976  {
8977  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8978  == ContinuationNameMap.end())
8979  {
8980  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8981  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8982  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8983  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8984  }
8985  }
8987  }
8988  Utilities->CallLogPop(578);
8989  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8990 // end of new section
8991 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8992 }
8993 
8994 // ---------------------------------------------------------------------------
8995 
8996 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8997 /*
8998  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8999  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9000  new names in the vectors.
9001 */
9002 {
9003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9004  bool FoundFlag, ErasedFlag = false;
9005  TLocationNameMultiMapIterator SNIterator;
9006  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9007 
9008  if(SNRange.first != SNRange.second)
9009  {
9010  ErasedFlag = true;
9011  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9012  {
9013  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9014  TVIt->LocationName = "";
9015  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9016  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9017  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9018  {
9019  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9020  if(FoundFlag)
9021  {
9022  TrackElementAt(25, Position).LocationName = "";
9023  TrackElementAt(26, Position).ActiveTrackElementName = "";
9024  }
9025  }
9026  }
9027  }
9028  if(ErasedFlag)
9029  {
9031  }
9032  CheckLocationNameMultiMap(3); // test
9033  Utilities->CallLogPop(579);
9034 }
9035 
9036 // ---------------------------------------------------------------------------
9037 
9038 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9039 /*
9040  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9041  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9042  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9043  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
9044  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
9045  naming up to date with the deletion or insertion.
9046 */
9047 {
9048  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9049  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9050  LNPendingList.clear();
9051  AnsiString LocationName;
9052  int MapPos;
9053  bool FoundFlag = 0;
9054 
9055 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9056  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9057  if(FoundFlag)
9058  {
9059  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9060  if(LocationName != "")
9061  {
9062  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9063  EnterLocationName(13, LocationName, true);
9064  Utilities->CallLogPop(2251);
9065  return;
9066  }
9067  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9068  if(LocationName != "")
9069  {
9070  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9071  EnterLocationName(14, LocationName, true);
9072  Utilities->CallLogPop(2252);
9073  return;
9074  }
9075  }
9076 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9077 
9078  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9079  if(FoundFlag)
9080  {
9081  LocationName = TrackElementAt(1004, Position).LocationName;
9082  if(LocationName != "")
9083  {
9084  int ModifiedPosition = -1 - Position;
9085  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9086  EnterLocationName(15, LocationName, true);
9087  Utilities->CallLogPop(2253);
9088  return;
9089  }
9090  }
9091  if(SpeedTag == 76) // top plat
9092  {
9093  for(int x = 0; x < 25; x++)
9094  {
9095  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9096  {
9097  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9098  EnterLocationName(3, LocationName, true);
9099  break;
9100  }
9101  }
9102  }
9103  else if(SpeedTag == 77) // bot plat
9104  {
9105  for(int x = 0; x < 25; x++)
9106  {
9107  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9108  {
9109  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9110  EnterLocationName(4, LocationName, true);
9111  break;
9112  }
9113  }
9114  }
9115  else if(SpeedTag == 78) // l plat
9116  {
9117  for(int x = 0; x < 25; x++)
9118  {
9119  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9120  {
9121  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9122  EnterLocationName(5, LocationName, true);
9123  break;
9124  }
9125  }
9126  }
9127  else if(SpeedTag == 79) // r plat
9128  {
9129  for(int x = 0; x < 25; x++)
9130  {
9131  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9132  {
9133  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9134  EnterLocationName(6, LocationName, true);
9135  break;
9136  }
9137  }
9138  }
9139  else if(SpeedTag == 96) // conc
9140  {
9141  for(int x = 0; x < 28; x++)
9142  {
9143  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9144  {
9145  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9146  EnterLocationName(7, LocationName, true);
9147  break;
9148  }
9149  }
9150  }
9151  else if(SpeedTag == 129) // vert footbridge
9152  {
9153  for(int x = 0; x < 8; x++)
9154  {
9155  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9156  {
9157  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9158  EnterLocationName(8, LocationName, true);
9159  break;
9160  }
9161  }
9162  }
9163  else if(SpeedTag == 130) // hor footbridge
9164  {
9165  for(int x = 0; x < 8; x++)
9166  {
9167  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9168  {
9169  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9170  EnterLocationName(9, LocationName, true);
9171  break;
9172  }
9173  }
9174  }
9175  else if(SpeedTag == 145) // vert u'pass
9176  {
9177  for(int x = 0; x < 8; x++)
9178  {
9179  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9180  {
9181  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9182  EnterLocationName(11, LocationName, true);
9183  break;
9184  }
9185  }
9186  }
9187  else if(SpeedTag == 146) // hor u'pass
9188  {
9189  for(int x = 0; x < 8; x++)
9190  {
9191  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9192  {
9193  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9194  EnterLocationName(12, LocationName, true);
9195  break;
9196  }
9197  }
9198  }
9199  else if(SpeedTag == 131) // named location
9200  {
9201  for(int x = 0; x < 4; x++)
9202  {
9203  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9204  {
9205  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9206  EnterLocationName(10, LocationName, true);
9207  break;
9208  }
9209  }
9210  }
9211 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9212  Utilities->CallLogPop(580);
9213 }
9214 
9215 // ---------------------------------------------------------------------------
9216 
9217 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9218 /*
9219  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9220  true if a LocationName is found, and also returns the name and the adjusted vector position.
9221 */
9222 {
9223  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9224  AnsiString(SpeedTag));
9225  bool FoundFlag;
9226  TIMPair IMPair;
9227  TTrackVectorIterator TempElement;
9228  int Position;
9229 
9230  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9231  if(FoundFlag)
9232  {
9233  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9234  {
9235  TempElement = InactiveTrackVector.begin() + IMPair.first;
9236  if(TempElement->LocationName != "")
9237  {
9238  LocationName = TempElement->LocationName;
9239  FoundElement = IMPair.first;
9240  Utilities->CallLogPop(581);
9241  return(true);
9242  }
9243  }
9244  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9245  {
9246  TempElement = InactiveTrackVector.begin() + IMPair.second;
9247  if(TempElement->LocationName != "")
9248  {
9249  LocationName = TempElement->LocationName;
9250  FoundElement = IMPair.second;
9251  Utilities->CallLogPop(582);
9252  return(true);
9253  }
9254  }
9255  }
9256  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9257  if(FoundFlag)
9258  {
9259  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9260  {
9261  TempElement = TrackVector.begin() + Position;
9262  if(TempElement->LocationName != "")
9263  {
9264  LocationName = TempElement->LocationName;
9265  FoundElement = -1 - Position;
9266  Utilities->CallLogPop(583);
9267  return(true);
9268  }
9269  }
9270  }
9271  Utilities->CallLogPop(584);
9272  return(false);
9273 }
9274 
9275 // ---------------------------------------------------------------------------
9276 
9277 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9278 {
9279 // check quantity in map & vectors match
9280  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9281  unsigned int Count = 0;
9282 
9283  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9284  {
9285  Utilities->CallLogPop(2059);
9286  return;
9287  }
9288  AnsiString SName, TName, ErrorString;
9289 
9290  for(unsigned int x = 0; x < TrackVector.size(); x++)
9291  {
9292  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9293  {
9294  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9295  {
9296  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9297  AnsiString(Caller));
9298  }
9299  Count++;
9300  }
9301  }
9302  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9303  {
9304  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9305  {
9306  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9307  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9308  {
9309  throw Exception
9310  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9311  AnsiString(Caller));
9312  }
9313  Count++;
9314  }
9315  }
9316  if(LocationNameMultiMap.size() != Count)
9317  {
9318  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9319  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9320  }
9321 // check all entries in both vectors match entries in name multimap
9323 
9324  for(unsigned int x = 0; x < TrackVector.size(); x++)
9325  {
9326  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9327  {
9328  SName = TrackElementAt(1365, x).LocationName;
9329  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9330  if(ErrorString != "")
9331  {
9332  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9333  }
9334  if(SNIt->second != -1 - (int)x)
9335  {
9336  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9337  AnsiString(Caller));
9338  }
9339  }
9340  // check corresponding platform for all Timetable entries that aren't empty
9341  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9342  TIMPair IMPair;
9343  bool FoundFlag = false;
9344  if(TName != "")
9345  {
9346  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9347  if(FoundFlag)
9348  {
9349  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9351  {
9352  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9353  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9354  }
9355  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9356  {
9357  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9358  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9359  AnsiString(Caller));
9360  }
9361  }
9362  else
9363  {
9364  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9365  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9366  }
9367  }
9368  }
9369  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9370  {
9371  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9372  {
9373  SName = InactiveTrackElementAt(148, x).LocationName;
9374  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9375  if(ErrorString != "")
9376  {
9377  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9378  }
9379  if(SNIt->second != (int)x)
9380  {
9381  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9382  AnsiString(Caller));
9383  }
9384  }
9385  }
9386  Utilities->CallLogPop(585);
9387 }
9388 
9389 // ---------------------------------------------------------------------------
9390 
9392  AnsiString &ErrorString)
9393 {
9394 /*
9395  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9396  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9397  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9398 */
9399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9400  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9401  ErrorString = "";
9402  bool FoundFlag = false;
9403  TLocationNameMultiMapIterator SNIterator;
9404  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9405 
9406  if(SNRange.first == SNRange.second)
9407  {
9408  ErrorString = "Error, Name " + LocationName + " not found in map";
9409  Utilities->CallLogPop(586);
9410  return(SNRange.first);
9411  }
9412  else
9413  {
9414  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9415  {
9416  if(SNIterator->second < 0)
9417  {
9418  int TVPos = -1 - SNIterator->second;
9419  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9420  if(TVIt == TrackElement)
9421  {
9422  FoundFlag = true;
9423  Utilities->CallLogPop(587);
9424  return(SNIterator);
9425  }
9426  }
9427  else
9428  {
9429  int ITVPos = SNIterator->second;
9430  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9431  if(ITVIt == TrackElement)
9432  {
9433  FoundFlag = true;
9434  Utilities->CallLogPop(588);
9435  return(SNIterator);
9436  }
9437  }
9438  }
9439  }
9440  if(!FoundFlag)
9441  {
9442  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9443  }
9444  Utilities->CallLogPop(589);
9445  return(SNIterator);
9446 }
9447 
9448 // ---------------------------------------------------------------------------
9449 
9450 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9451 {
9452 /*
9453  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9454  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9455 */
9456  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9457  TLocationNameMultiMapEntry LocationNameEntry;
9458 
9459  LocationNameEntry.first = NewName;
9460  LocationNameEntry.second = SNIterator->second;
9461  LocationNameMultiMap.erase(SNIterator);
9462  LocationNameMultiMap.insert(LocationNameEntry);
9463  Utilities->CallLogPop(590);
9464 }
9465 
9466 // ---------------------------------------------------------------------------
9467 
9469 {
9470 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9472  if(Position < 0) // footcrossing
9473  {
9474  int TruePos = -1 - Position;
9475  // new check at v0.2b
9476  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9477  {
9478  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9479  }
9480  Utilities->CallLogPop(591);
9481  return (TrackVector.begin() + TruePos);
9482  }
9483  else
9484  {
9485  // new check at v0.2b
9486  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9487  {
9488  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9489  }
9490  Utilities->CallLogPop(592);
9491  return (InactiveTrackVector.begin() + Position);
9492  }
9493 }
9494 
9495 // ---------------------------------------------------------------------------
9496 
9497 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9498 {
9499 /*
9500  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9501  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9502  LocationNameMultiMap.
9503 */
9504  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9505  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9506  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9507 
9508  if(!InactiveTrack2MultiMap.empty())
9509  {
9510  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9511  InactiveTrack2MultiMapIterator++)
9512  {
9513  if(InactiveTrack2MultiMapIterator->second > VecPos)
9514  {
9515  InactiveTrack2MultiMapIterator->second--;
9516  }
9517  // can't be == VecPos as that position erased
9518  }
9519  }
9520  if(!LocationNameMultiMap.empty())
9521  {
9522  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9523  LocationNameMultiMapIterator++)
9524  {
9525  if(LocationNameMultiMapIterator->second < 0)
9526  {
9527  continue; // deal with TrackVectors separately
9528  }
9529  if(LocationNameMultiMapIterator->second > (int)VecPos)
9530  {
9531  LocationNameMultiMapIterator->second--;
9532  }
9533  }
9534  }
9535  Utilities->CallLogPop(593);
9536 }
9537 
9538 // ---------------------------------------------------------------------------
9539 
9540 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9541 {
9542 /*
9543  After an element has been erased from the track vector, all the later elements are moved down one. This function
9544  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9545  LocationNameMultiMap.
9546 */
9547  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9548  TTrackMapIterator TrackMapIterator;
9549  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9550 
9551  if(!TrackMap.empty())
9552  {
9553  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9554  {
9555  if(TrackMapIterator->second > VecPos)
9556  {
9557  TrackMapIterator->second--;
9558  }
9559  // can't be == VecPos as that position erased
9560  }
9561  }
9562  if(!LocationNameMultiMap.empty())
9563  {
9564  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9565  LocationNameMultiMapIterator++)
9566  {
9567  if(LocationNameMultiMapIterator->second >= 0)
9568  {
9569  continue; // deal with InactiveTrackVectors separately
9570  }
9571  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9572  // Val -1 -2 -3 -4 -5 -6 -7 -8
9573  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9574  {
9575  LocationNameMultiMapIterator->second++;
9576  }
9577  }
9578  }
9579  for(unsigned int x = 0; x < TrackVector.size(); x++)
9580  {
9581  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9582  if(TkEl.TrackType == GapJump)
9583  {
9584  // position 0 is the gap
9585  if(TkEl.Conn[0] == int(VecPos))
9586  {
9587  TkEl.Conn[0] = -1; // connected to a deleted gap
9588  continue;
9589  }
9590  if(TkEl.Conn[0] > int(VecPos))
9591  {
9592  TkEl.Conn[0]--;
9593  }
9594  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9595  {
9596  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9597  {
9598  TkEl.Conn[0] = -1;
9599  }
9600  }
9601  }
9602  }
9603  Utilities->CallLogPop(1433);
9604 }
9605 
9606 // ---------------------------------------------------------------------------
9607 
9609 /*
9610  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9611  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9612  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9613 */
9614 {
9615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9616  LocationNameMultiMap.clear();
9617  TLocationNameMultiMapEntry LocationNameEntry;
9618  TTrackElement TrackElement;
9619 
9620  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9621  {
9622  TrackElement = TrackElementAt(1376, TVPos);
9623  if(TrackElement.FixedNamedLocationElement)
9624  {
9625  LocationNameEntry.first = TrackElement.LocationName;
9626  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9627  LocationNameMultiMap.insert(LocationNameEntry);
9628  }
9629  }
9630 
9631  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9632  {
9633  TrackElement = InactiveTrackElementAt(149, ITVPos);
9634  if(TrackElement.FixedNamedLocationElement)
9635  {
9636  LocationNameEntry.first = TrackElement.LocationName;
9637  LocationNameEntry.second = ITVPos;
9638  LocationNameMultiMap.insert(LocationNameEntry);
9639  }
9640  }
9641  Utilities->CallLogPop(594);
9642 }
9643 
9644 // ---------------------------------------------------------------------------
9645 
9647 // Return true if there is a named location present in the railway
9648 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9649 {
9650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9651  TTrackVectorIterator ITVI;
9652 
9653  if(InactiveTrackVector.empty())
9654  {
9655  Utilities->CallLogPop(1343);
9656  return(false);
9657  }
9658  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9659  {
9660  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9661  {
9662  Utilities->CallLogPop(1404);
9663  return(true);
9664  }
9665  }
9666  Utilities->CallLogPop(1344);
9667  return(false);
9668 }
9669 
9670 // ---------------------------------------------------------------------------
9671 
9673 /*
9674  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9675 */
9676 {
9677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9678 // ResetDistanceElements(6);
9679  for(unsigned int x = 0; x < TrackVector.size(); x++)
9680  {
9681  TTrackElement &TE = TrackElementAt(718, x);
9684  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9685  {
9688  }
9689  }
9690 /* old function
9691  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9692  {
9693  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9694  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9695  }
9696  else
9697  {
9698  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9699  }
9700  }
9701 */
9702  Utilities->CallLogPop(617);
9703 }
9704 
9705 // ---------------------------------------------------------------------------
9706 
9707 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9708 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9709 {
9710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9711  for(unsigned int x = 0; x < TrackVector.size(); x++)
9712  {
9713  TTrackElement TempElement = TrackElementAt(1377, x);
9714  if(TempElement.Length01 > -1)
9715  {
9716  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9717  }
9718  if(TempElement.Length23 > -1)
9719  {
9720  MarkOneLength(2, TempElement, false, Disp);
9721  }
9722  }
9723  Disp->Update();
9724  Utilities->CallLogPop(618);
9725 }
9726 
9727 // ---------------------------------------------------------------------------
9728 
9729 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9730 /*
9731  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9732  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9733  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9734  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9735  track as indicated by FirstTrack (true for track01 & false for track23).
9736 */
9737 {
9738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9739  AnsiString((short)FirstTrack));
9740  bool LengthDifferent = false, SpeedDifferent = false;
9741 
9742  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9743  {
9744  Utilities->CallLogPop(619);
9745  return;
9746  }
9747  int EXArray[16][2] =
9748  {{4, 6}, {2, 8}, // horizontal & vertical
9749  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9750  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9751  {1, 9}, {3, 7}}; // forward & reverse diagonals
9752 
9753  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9754  Graphics::TBitmap *Bitmap;
9755 
9756  if(FirstTrack)
9757  {
9758  InLink = TrackElement.Link[0];
9759  OutLink = TrackElement.Link[1];
9760  }
9761  else
9762  {
9763  InLink = TrackElement.Link[2];
9764  OutLink = TrackElement.Link[3];
9765  }
9766  for(int x = 0; x < 16; x++)
9767  {
9768  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9769  {
9770  Index = x;
9771  }
9772  }
9773  if(Index == -1)
9774  {
9775  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9776  }
9777 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9778  the graphic for each of which is different because of the shape of the overbridge. The basic
9779  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9780  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9781  int BrEXArray[24][2] = {
9782  {4,6},{2,8},{1,9},{3,7},
9783  {1,9},{3,7},{1,9},{3,7},
9784  {2,8},{4,6},{2,8},{4,6}
9785 */
9786  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9787  {
9788  if(Index == 1)
9789  {
9790  if(TrackElement.SpeedTag == 49)
9791  {
9792  BrNum = 1 + 16;
9793  }
9794  else if(TrackElement.SpeedTag == 54)
9795  {
9796  BrNum = 8 + 16;
9797  }
9798  else if(TrackElement.SpeedTag == 55)
9799  {
9800  BrNum = 10 + 16;
9801  }
9802  }
9803  else if(Index == 0)
9804  {
9805  if(TrackElement.SpeedTag == 48)
9806  {
9807  BrNum = 0 + 16;
9808  }
9809  else if(TrackElement.SpeedTag == 58)
9810  {
9811  BrNum = 11 + 16;
9812  }
9813  else if(TrackElement.SpeedTag == 59)
9814  {
9815  BrNum = 9 + 16;
9816  }
9817  }
9818  else if(Index == 14)
9819  {
9820  if(TrackElement.SpeedTag == 50)
9821  {
9822  BrNum = 2 + 16;
9823  }
9824  else if(TrackElement.SpeedTag == 52)
9825  {
9826  BrNum = 4 + 16;
9827  }
9828  else if(TrackElement.SpeedTag == 57)
9829  {
9830  BrNum = 6 + 16;
9831  }
9832  }
9833  else if(Index == 15)
9834  {
9835  if(TrackElement.SpeedTag == 51)
9836  {
9837  BrNum = 3 + 16;
9838  }
9839  else if(TrackElement.SpeedTag == 53)
9840  {
9841  BrNum = 7 + 16;
9842  }
9843  else if(TrackElement.SpeedTag == 56)
9844  {
9845  BrNum = 5 + 16;
9846  }
9847  }
9848  }
9849  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9850  {
9851  GrNum = BrNum;
9852  }
9853  else
9854  {
9855  GrNum = Index;
9856  }
9857  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9858  {
9859  if(GrNum > 15) // underbridge
9860  {
9861  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9862  }
9863  else
9864  {
9865  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9866  }
9867  if(TrackElement.SpeedTag == 64)
9868  {
9869  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9870  }
9871  if(TrackElement.SpeedTag == 65)
9872  {
9874  }
9875  if(TrackElement.SpeedTag == 66)
9876  {
9878  }
9879  if(TrackElement.SpeedTag == 67)
9880  {
9882  }
9883  if(TrackElement.SpeedTag == 80)
9884  {
9885  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9886  }
9887  if(TrackElement.SpeedTag == 81)
9888  {
9890  }
9891  if(TrackElement.SpeedTag == 82)
9892  {
9894  }
9895  if(TrackElement.SpeedTag == 83)
9896  {
9898  }
9899  if(TrackElement.SpeedTag == 84)
9900  {
9902  }
9903  if(TrackElement.SpeedTag == 85)
9904  {
9906  }
9907  if(TrackElement.SpeedTag == 86)
9908  {
9910  }
9911  if(TrackElement.SpeedTag == 87)
9912  {
9914  }
9915  if(TrackElement.SpeedTag == 129)
9916  {
9917  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9918  }
9919  if(TrackElement.SpeedTag == 130)
9920  {
9922  }
9923  }
9924 
9925  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9926  {
9927  if(GrNum > 15) // underbridge
9928  {
9929  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9930  }
9931  else
9932  {
9933  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9934  }
9935  if(TrackElement.SpeedTag == 64)
9936  {
9937  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9938  }
9939  if(TrackElement.SpeedTag == 65)
9940  {
9941  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9942  }
9943  if(TrackElement.SpeedTag == 66)
9944  {
9945  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9946  }
9947  if(TrackElement.SpeedTag == 67)
9948  {
9949  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9950  }
9951  if(TrackElement.SpeedTag == 80)
9952  {
9953  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9954  }
9955  if(TrackElement.SpeedTag == 81)
9956  {
9957  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9958  }
9959  if(TrackElement.SpeedTag == 82)
9960  {
9961  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9962  }
9963  if(TrackElement.SpeedTag == 83)
9964  {
9965  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9966  }
9967  if(TrackElement.SpeedTag == 84)
9968  {
9969  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9970  }
9971  if(TrackElement.SpeedTag == 85)
9972  {
9973  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9974  }
9975  if(TrackElement.SpeedTag == 86)
9976  {
9977  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9978  }
9979  if(TrackElement.SpeedTag == 87)
9980  {
9981  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9982  }
9983  if(TrackElement.SpeedTag == 129)
9984  {
9985  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9986  }
9987  if(TrackElement.SpeedTag == 130)
9988  {
9989  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9990  }
9991  }
9992 
9993  else // SpeedDifferent only: red - use non sig graphics
9994  {
9995  if(GrNum > 15) // underbridge
9996  {
9997  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9998  }
9999  else
10000  {
10001  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10002  }
10003  if(TrackElement.SpeedTag == 64)
10004  {
10005  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10006  }
10007  if(TrackElement.SpeedTag == 65)
10008  {
10010  }
10011  if(TrackElement.SpeedTag == 66)
10012  {
10014  }
10015  if(TrackElement.SpeedTag == 67)
10016  {
10018  }
10019  if(TrackElement.SpeedTag == 80)
10020  {
10021  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10022  }
10023  if(TrackElement.SpeedTag == 81)
10024  {
10026  }
10027  if(TrackElement.SpeedTag == 82)
10028  {
10030  }
10031  if(TrackElement.SpeedTag == 83)
10032  {
10034  }
10035  if(TrackElement.SpeedTag == 84)
10036  {
10038  }
10039  if(TrackElement.SpeedTag == 85)
10040  {
10042  }
10043  if(TrackElement.SpeedTag == 86)
10044  {
10046  }
10047  if(TrackElement.SpeedTag == 87)
10048  {
10050  }
10051  if(TrackElement.SpeedTag == 129)
10052  {
10053  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10054  }
10055  if(TrackElement.SpeedTag == 130)
10056  {
10058  }
10059  }
10060  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10061  Utilities->CallLogPop(620);
10062 }
10063 
10064 // ---------------------------------------------------------------------------
10065 
10066 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10067 /* FirstTrack = LinkPos's 0 & 1
10068  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10069 */
10070 {
10071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10072  AnsiString((short)FirstTrack));
10073  LengthDifferent = false;
10074  SpeedDifferent = false;
10075  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10076  {
10077  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10078  {
10079  LengthDifferent = true;
10080  }
10081  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10082  {
10083  SpeedDifferent = true;
10084  }
10085  if(LengthDifferent || SpeedDifferent)
10086  {
10087  Utilities->CallLogPop(625);
10088  return(false);
10089  }
10090  Utilities->CallLogPop(626);
10091  return(true);
10092  }
10093 
10094  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10095  {
10096  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10097  {
10098  LengthDifferent = true;
10099  }
10100  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10101  {
10102  SpeedDifferent = true;
10103  }
10104  if(LengthDifferent || SpeedDifferent)
10105  {
10106  Utilities->CallLogPop(627);
10107  return(false);
10108  }
10109  Utilities->CallLogPop(628);
10110  return(true);
10111  }
10112 
10113  else // any other 1 track element, including platforms being present
10114  {
10115  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10116  {
10117  LengthDifferent = true;
10118  }
10119  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10120  {
10121  SpeedDifferent = true;
10122  }
10123  if(LengthDifferent || SpeedDifferent)
10124  {
10125  Utilities->CallLogPop(629);
10126  return(false);
10127  }
10128  Utilities->CallLogPop(630);
10129  return(true);
10130  }
10131 }
10132 
10133 // ---------------------------------------------------------------------------
10134 
10135 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10136 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10137 {
10138  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10139  AnsiString(VLoc));
10140  bool FoundFlag;
10141  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10142 
10143  if(!FoundFlag)
10144  {
10145  Utilities->CallLogPop(633);
10146  return(false);
10147  }
10148  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10149  {
10150  Utilities->CallLogPop(634);
10151  return(true); // only need to check first since if second is a platform the the first must be too
10152  }
10153  else
10154  {
10155  Utilities->CallLogPop(635);
10156  return(false);
10157  }
10158 }
10159 
10160 // ---------------------------------------------------------------------------
10161 
10162 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10163 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10164 {
10165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10166  AnsiString(VLoc));
10167  bool FoundFlag;
10168  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10169 
10170  if(!FoundFlag)
10171  {
10172  Utilities->CallLogPop(636);
10173  return(false);
10174  }
10176  {
10177  Utilities->CallLogPop(637);
10178  return(true); // only need to check first since only one used for NamedNonStationLocations
10179  }
10180  else
10181  {
10182  Utilities->CallLogPop(638);
10183  return(false);
10184  }
10185 }
10186 
10187 // ---------------------------------------------------------------------------
10188 
10190 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10191  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10192  the front of train stop points for each direction.
10193  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10194  end (unless buffers at one or both ends in which case stop points are the end elements).
10195  Note that for a single element the stop point is the element itself (formula doesn't apply).
10196  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10197  repeating the procedure for every element. At the end all unused values are returned to -1.
10198  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10199 */
10200 {
10201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10202  TTrackElement TempElement, StartElement;
10203  AnsiString TempName;
10204  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10205  bool ForwardSet, ReverseSet;
10206 
10207  for(unsigned int x = 0; x < TrackVector.size(); x++)
10208  {
10211  }
10212  for(unsigned int x = 0; x < TrackVector.size(); x++)
10213  {
10214  ForwardSet = false;
10215  ReverseSet = false;
10216  TempElement = TrackElementAt(1380, x);
10217  VecPos = x;
10218  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10219  // 2nd condition incl so don't re-examine elements with stop links set to 5
10220  {
10221  TempName = TempElement.ActiveTrackElementName;
10222  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10223  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10224  // an element linked at both ends where both links are also named elements
10225  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10226  {
10227  continue; // looking for an end element so skip this one
10228  }
10229  else // reached one end
10230  {
10231  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10232  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10233  // single named element linked at both ends
10234  {
10235  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10236  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10237  continue;
10238  }
10239  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10240  // single named buffer element (LinkPos 1 is the non-buffer end)
10241  {
10242  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10243  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10244  continue;
10245  }
10246  else
10247  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10248  // and platforms always on straight (conns 0 & 1) section of points
10249  {
10250  for(int y = 0; y < 2; y++)
10251  {
10252  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10253  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10254 /* TTrackElement Temp1 = TempElement;
10255  ***********New section, compiles but not checked - does bit below need to be else if?
10256  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10257  {
10258  //search along Dir direction until find other end, skip if Dir facing buffer end
10259  int NewDir = Dir;
10260  int NewVecPos;
10261  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10262  {
10263  NewVecPos = Temp1.Conn[NewDir];
10264  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10265  Temp1 = TrackElementAt(601, NewVecPos);
10266  }
10267  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10268  {
10269  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10270  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10271  }
10272  }
10273  ***************
10274 */
10275  // end may be linked at both ends but only one link named, or buffer with linked element named
10276  // if a buffer then the named linkpos has to be 1
10277  // already dealt with all types of single element so at least 2 linked named element
10278  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10279  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10280  {
10281  StartElement = TempElement;
10282  StartVecPos = VecPos;
10283  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10284  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10285  EntryPos = 1 - Dir;
10286  StartEntryPos = 1 - Dir;
10287  Count = 1;
10288  // work along named elements until find the other end
10289  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10290  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10291  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10292  // all stop link pos's are set to 5
10293  {
10294  VecPos = TempElement.Conn[1 - EntryPos];
10295  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10296  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10297  EntryPos = TempEntryPos;
10298  Count++;
10299  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10300  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10301  }
10302  // here when reached other end, maybe buffers, continuation or last named linked element
10303  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10304  // terminal station, set end elements as stop elements
10305  {
10306  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10307  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10308  continue;
10309  }
10310  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10311  // terminal station, set end elements as stop elements
10312  {
10313  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10314  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10315  continue;
10316  }
10317  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10318  // NonStationLocation so set end elements as stop elements
10319  {
10320  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10321  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10322  continue;
10323  }
10324  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10325  ForwardNumber = ((Count + 1) / 2) + 1;
10326  ReverseNumber = (Count - ForwardNumber) + 1;
10327  Count = 1; // starting value
10328  EntryPos = 1 - Dir;
10329  TempElement = StartElement;
10330  VecPos = StartVecPos;
10331  if(Count == ForwardNumber)
10332  {
10333  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10334  ForwardSet = true;
10335  }
10336  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10337  {
10338  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10339  ReverseSet = true;
10340  }
10341  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10342  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10343  {
10344  VecPos = TempElement.Conn[1 - EntryPos];
10345  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10346  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10347  EntryPos = TempEntryPos;
10348  Count++;
10349  if(Count == ForwardNumber)
10350  {
10351  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10352  ForwardSet = true;
10353  }
10354  if(Count == ReverseNumber)
10355  {
10356  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10357  ReverseSet = true;
10358  }
10359  }
10360  }
10361  }
10362  }
10363  }
10364  }
10365  }
10366  for(unsigned int x = 0; x < TrackVector.size(); x++)
10367  {
10368  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10369  {
10371  }
10372  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10373  {
10375  }
10376  }
10377  Utilities->CallLogPop(639);
10378 }
10379 
10380 // ---------------------------------------------------------------------------
10381 
10382 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10383 {
10384  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10385  TTrackElement Next;
10386 
10388  while(ReturnNextInactiveTrackElement(1, Next))
10389  {
10390  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10391  {
10392  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10393  // need striped graphics
10394  {
10395  if(Next.SpeedTag == 76)
10396  {
10397  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10398  }
10399  else if(Next.SpeedTag == 77)
10400  {
10401  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10402  }
10403  else if(Next.SpeedTag == 78)
10404  {
10405  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10406  }
10407  else if(Next.SpeedTag == 79)
10408  {
10409  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10410  }
10411  else if(Next.SpeedTag == 96)
10412  {
10413  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10414  }
10415  else if(Next.SpeedTag == 131)
10416  {
10417  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10418  }
10419  }
10420  else
10421  {
10422  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10423  }
10424  }
10425  }
10426 
10427  NextTrackElementPtr = TrackVector.begin();
10428  while(ReturnNextTrackElement(1, Next))
10429  {
10430  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10431  {
10432  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10433  {
10434  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10435  {
10436  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10437  }
10438  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10439  {
10440  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10441  }
10442  }
10443  else
10444  {
10445  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10446  }
10447  }
10448  }
10449  Disp->Update();
10450  Utilities->CallLogPop(640);
10451 }
10452 
10453 // ---------------------------------------------------------------------------
10454 
10455 void TTrack::PlotSmallRedGap(int Caller)
10456 {
10457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10459  Utilities->CallLogPop(1346);
10460 }
10461 
10462 // ---------------------------------------------------------------------------
10463 
10464 void TTrack::TrackClear(int Caller)
10465 {
10466  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10467  TrackVector.clear();
10468  InactiveTrackVector.clear();
10469  TrackMap.clear();
10471  if(TextHandler->TextVector.size() == 0)
10472  {
10473  Display->DisplayOffsetH = 0;
10474  Display->DisplayOffsetV = 0;
10481  HLocMin = 2000000000;
10482  HLocMax = -2000000000;
10483  VLocMin = 2000000000;
10484  VLocMax = -2000000000;
10485  }
10486  else
10487  {
10488  CalcHLocMinEtc(4);
10489  }
10490  Utilities->CallLogPop(1347);
10491 }
10492 
10493 // ---------------------------------------------------------------------------
10494 
10495 void TTrack::CalcHLocMinEtc(int Caller)
10496 {
10497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10498  HLocMin = 2000000000;
10499  VLocMin = 2000000000;
10500  HLocMax = -2000000000;
10501  VLocMax = -2000000000;
10502  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10503  {
10504  if(TrackElementAt(1385, x).SpeedTag == 0)
10505  {
10506  continue; // skip erase elements or would interfere with Min & Max values
10507  }
10508  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10509  {
10510  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10511  }
10512  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10513  {
10514  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10515  }
10516  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10517  {
10518  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10519  }
10520  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10521  {
10522  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10523  }
10524  }
10525  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10526  {
10527  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10528  {
10529  continue; // shouldn't be any inactive erase elements but include anyway
10530  }
10531  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10532  {
10533  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10534  }
10535  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10536  {
10537  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10538  }
10539  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10540  {
10541  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10542  }
10543  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10544  {
10545  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10546  }
10547  }
10548  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10549  {
10550 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10551  will fail as x will exceed the maximum value
10552  if(TextHandler->TextPtrAt(, x)->TextString == "")
10553  {
10554  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10555  }
10556 */
10557  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10558  if((TextH / 16) - 1 < HLocMin)
10559  {
10560  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10561  }
10562  if((TextH / 16) + 1 > HLocMax)
10563  {
10564  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10565  }
10566  if((TextV / 16) - 1 < VLocMin)
10567  {
10568  VLocMin = (TextV / 16) - 1;
10569  }
10570  if((TextV / 16) + 1 > VLocMax)
10571  {
10572  VLocMax = (TextV / 16) + 1;
10573  }
10574  }
10575  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10576  {
10577  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10578  {
10579  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10580  }
10581  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10582  {
10583  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10584  }
10585  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10586  {
10587  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10588  }
10589  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10590  {
10591  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10592  }
10593  }
10594 
10595  Utilities->CallLogPop(641);
10596 }
10597 
10598 // ---------------------------------------------------------------------------
10599 
10600 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10601  bool &UserGraphicFoundFlag)
10602 {
10603  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10604  TUserGraphicVector::iterator UserGraphicPtr;
10605 
10606  UserGraphicFoundFlag = false;
10607  if(!UserGraphicVector.empty())
10608  {
10609  int x = UserGraphicVector.size();
10610  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10611  {
10612  x--;
10613  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10614  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10615  {
10616  UserGraphicItem = x;
10617  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10618  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10619  UserGraphicFoundFlag = true;
10620  Utilities->CallLogPop(2177);
10621  return;
10622  } // if ....
10623 
10624  } // for UserGraphicPtr...
10625  } // if !UserGraphicVector...
10626 
10627  Utilities->CallLogPop(2197);
10628 }
10629 
10630 // ---------------------------------------------------------------------------
10631 
10633 {
10634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10635  TrackElement.LogTrack(11));
10636  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10637  int SpeedTag = TrackElement.SpeedTag;
10638 
10639  if(SpeedTag < 1)
10640  {
10641  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10642  }
10643  switch(SpeedTag)
10644  {
10645  case 76: // t platform
10646  GraphicOutput = RailGraphics->gl76Striped;
10647  break;
10648 
10649  case 77: // h platform
10650  GraphicOutput = RailGraphics->bm77Striped;
10651  break;
10652 
10653  case 78: // v platform
10654  GraphicOutput = RailGraphics->bm78Striped;
10655  break;
10656 
10657  case 79: // r platform
10658  GraphicOutput = RailGraphics->gl79Striped;
10659  break;
10660 
10661  case 96: // concourse
10662  GraphicOutput = RailGraphics->ConcourseStriped;
10663  break;
10664 
10665  case 129: // v footbridge
10666  GraphicOutput = RailGraphics->gl129Striped;
10667  break;
10668 
10669  case 130: // h footbridge
10670  GraphicOutput = RailGraphics->gl130Striped;
10671  break;
10672 
10673  case 131: // non-station named loc
10674  GraphicOutput = RailGraphics->bmNameStriped;
10675  break;
10676 
10677  case 145: // v u'pass
10678  GraphicOutput = RailGraphics->gl145Striped;
10679  break;
10680 
10681  case 146: // h u'pass
10682  GraphicOutput = RailGraphics->gl146Striped;
10683  break;
10684 
10685  default:
10686  GraphicOutput = TrackElement.GraphicPtr;
10687  break;
10688  }
10689  Utilities->CallLogPop(642);
10690  return(GraphicOutput);
10691 }
10692 
10693 // ---------------------------------------------------------------------------
10694 
10696 {
10697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10698  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10699  {
10700 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10701  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10702  }
10703  Utilities->CallLogPop(643);
10704  return(TrackVector.at(At));
10705 }
10706 
10707 // ---------------------------------------------------------------------------
10708 
10710 {
10711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10712  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10713  {
10714  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10715  " in InactiveTrackElementAt");
10716  }
10717  Utilities->CallLogPop(644);
10718  return(InactiveTrackVector.at(At));
10719 }
10720 
10721 // ---------------------------------------------------------------------------
10722 
10723 bool TTrack::BlankElementAt(int Caller, int At) const
10724 {
10725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10726  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10727  {
10728  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10729  }
10730  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10731  {
10732  Utilities->CallLogPop(645);
10733  return(true);
10734  }
10735  else
10736  {
10737  Utilities->CallLogPop(646);
10738  return(false);
10739  }
10740 }
10741 
10742 // ---------------------------------------------------------------------------
10743 
10744 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10745 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10746  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10747  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10748  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10749  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10750 */
10751 {
10752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10753  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10754  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10755  TLocationNameMultiMapIterator SNIterator;
10756  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10757 
10758  if(SNRange.first == SNRange.second)
10759  {
10760  Utilities->CallLogPop(972);
10761  return(false); // should have been caught earlier but include for completeness
10762  }
10763  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10764  {
10765  if(SNIterator->second < 0)
10766  {
10767  continue; // exclude footcrossings
10768  }
10769  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10770  if(InactiveElement.TrackType == Concourse)
10771  {
10772  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10773  }
10774  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10775  {
10776  continue; // only interested in locations where ActiveTrackElementName may be set
10777  }
10778  THVPair HVPair;
10779  HVPair.first = InactiveElement.HLoc;
10780  HVPair.second = InactiveElement.VLoc;
10781  if(TrackMap.find(HVPair) == TrackMap.end())
10782  {
10783  throw Exception
10784  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10785  }
10786  int TVPos = TrackMap.find(HVPair)->second;
10787  FirstNamedElement = TrackElementAt(560, TVPos);
10788  // first check linked on both sides, skip the check if not
10789  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10790  {
10791  continue;
10792  }
10793  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10794  // ActiveTrackElementNames are points and excluding trailing connections for points
10795  FirstNamedExitPos = 0;
10796  {
10797  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10798  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10799  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10800  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10801  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10802  {
10803  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10804  {
10805  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10806  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10807  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10808  // success, now check FirstNamedElement link not trailing points & if so all OK
10809  {
10810  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10811  {
10812  Utilities->CallLogPop(1002);
10813  return(true);
10814  }
10815  }
10816  }
10817  }
10818  }
10819  // failed, try link 1
10820  FirstNamedExitPos = 1;
10821  {
10822  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10823  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10824  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10825  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10826  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10827  {
10828  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10829  {
10830  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10831  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10832  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10833  // success, now check FirstNamedElement link not trailing points & if so all OK
10834  {
10835  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10836  {
10837  Utilities->CallLogPop(1003);
10838  return(true);
10839  }
10840  }
10841  }
10842  }
10843  }
10844  }
10845  Utilities->CallLogPop(1004);
10846  return(false);
10847 }
10848 
10849 // ---------------------------------------------------------------------------
10850 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10851  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10852 // for success need two linked named location elements, so that one element of each train can be at the location
10853 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10854 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10855 // the two trains will occupy these 4 elements
10856 // All are track vector positions, all but the input being references and set within the function.
10857 {
10858 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10859  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10860  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10861  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10862  splitting.
10863 */
10864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10865  AnsiString(FirstNamedElementPos));
10866  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10867  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10868 
10869  SecondNamedElementPos = -1;
10870  FirstNamedLinkedElementPos = -1;
10871  SecondNamedLinkedElementPos = -1;
10872  TLocationNameMultiMapIterator SNIterator;
10873  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10874 
10875  if(SNRange.first == SNRange.second) // i.e. location name not in map
10876  {
10877  Utilities->CallLogPop(1005);
10878  return(false); // should have been caught earlier but include for completeness
10879  }
10880  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10881  {
10882  if(SNIterator->second < 0)
10883  {
10884  continue; // exclude footcrossings
10885  }
10886  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10887  if(InactiveElement.TrackType == Concourse)
10888  {
10889  continue; // only interested in locations where ActiveTrackElementName may be set
10890  }
10891  THVPair HVPair;
10892  HVPair.first = InactiveElement.HLoc;
10893  HVPair.second = InactiveElement.VLoc;
10894  if(TrackMap.find(HVPair) == TrackMap.end())
10895  {
10896  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10897  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10898  // then it won't be found in TrackMap but it's still legitimate.
10899  {
10900  continue;
10901  }
10902  else // for anything else throw the error
10903  {
10904  throw Exception
10905  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10906  );
10907  }
10908  }
10909  int TVPos = TrackMap.find(HVPair)->second;
10910  if(TVPos != FirstNamedElementPos)
10911  {
10912  continue; // looking for an exact match
10913  }
10914  FirstNamedElement = TrackElementAt(567, TVPos);
10915  // first check linked on both sides, skip the check if not
10916  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10917  {
10918  continue;
10919  }
10920  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10921  // ActiveTrackElementNames are points and excluding trailing connections for points
10922  FirstNamedExitPos = 0;
10923  {
10924  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10925  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10926  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10927  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10928  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10929  {
10930  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10931  {
10932  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10933  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10934  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10935  // success, now check FirstNamedElement link not trailing points & if so all OK
10936  {
10937  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10938  {
10939  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10940  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10941  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10942  Utilities->CallLogPop(1006);
10943  return(true);
10944  }
10945  }
10946  }
10947  }
10948  }
10949  // failed, try link 1
10950  FirstNamedExitPos = 1;
10951  {
10952  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10953  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10954  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10955  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10956  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10957  {
10958  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10959  {
10960  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10961  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10962  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10963  // success, now check FirstNamedElement link not trailing points & if so all OK
10964  {
10965  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10966  {
10967  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10968  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10969  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10970  Utilities->CallLogPop(1007);
10971  return(true);
10972  }
10973  }
10974  }
10975  }
10976  }
10977  }
10978  Utilities->CallLogPop(1008);
10979  return(false);
10980 }
10981 
10982 // ---------------------------------------------------------------------------
10983 
10984 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10985 {
10986  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10987  TLocationNameMultiMapIterator SNIterator;
10988  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10989 
10990  if(SNRange.first != SNRange.second)
10991  {
10992  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10993  {
10994  if(SNIterator->second < 0)
10995  {
10996  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10997  }
10998  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10999  SNIterator->second).TrackType == NamedNonStationLocation))
11000  {
11001  Utilities->CallLogPop(1121);
11002  return(true);
11003  }
11004  }
11005  }
11006  Utilities->CallLogPop(848);
11007  return(false);
11008 }
11009 
11010 // ---------------------------------------------------------------------------
11011 
11012 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11013 {
11014 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11016  "," + AnsiString(SpeedTag));
11017  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11018  {
11019  Utilities->CallLogPop(949);
11020  return(false);
11021  }
11022  bool FoundFlag;
11023  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11024 
11025  if(!FoundFlag)
11026  {
11027  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11028  }
11029  TTrackElement IAElement;
11030 
11031  if(SpeedTag == 68) // top sig
11032  {
11033  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11034  {
11035  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11036  {
11037  IAElement = InactiveTrackElementAt(50, IMPair.first);
11038  }
11039  else
11040  {
11041  IAElement = InactiveTrackElementAt(51, IMPair.second);
11042  }
11043  if(IAElement.LocationName == "")
11044  {
11045 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11046  SignalPlatformGraphic = RailGraphics->gl76Striped;
11047  }
11048  else
11049  {
11050 // SignalPlatformGraphic = RailGraphics->Plat68;
11051  SignalPlatformGraphic = RailGraphics->gl76;
11052  }
11053  Utilities->CallLogPop(950);
11054  return(true);
11055  }
11056  }
11057  else if(SpeedTag == 69) // bot sig
11058  {
11059  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11060  {
11061  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11062  {
11063  IAElement = InactiveTrackElementAt(77, IMPair.first);
11064  }
11065  else
11066  {
11067  IAElement = InactiveTrackElementAt(78, IMPair.second);
11068  }
11069  if(IAElement.LocationName == "")
11070  {
11071 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11072  SignalPlatformGraphic = RailGraphics->bm77Striped;
11073  }
11074  else
11075  {
11076 // SignalPlatformGraphic = RailGraphics->Plat69;
11077  SignalPlatformGraphic = RailGraphics->bm77;
11078  }
11079  Utilities->CallLogPop(951);
11080  return(true);
11081  }
11082  }
11083  else if(SpeedTag == 70) // left sig
11084  {
11085  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11086  {
11087  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11088  {
11089  IAElement = InactiveTrackElementAt(55, IMPair.first);
11090  }
11091  else
11092  {
11093  IAElement = InactiveTrackElementAt(82, IMPair.second);
11094  }
11095  if(IAElement.LocationName == "")
11096  {
11097 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11098  SignalPlatformGraphic = RailGraphics->bm78Striped;
11099  }
11100  else
11101  {
11102 // SignalPlatformGraphic = RailGraphics->Plat70;
11103  SignalPlatformGraphic = RailGraphics->bm78;
11104  }
11105  Utilities->CallLogPop(952);
11106  return(true);
11107  }
11108  }
11109  else if(SpeedTag == 71) // right sig
11110  {
11111  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11112  {
11113  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11114  {
11115  IAElement = InactiveTrackElementAt(85, IMPair.first);
11116  }
11117  else
11118  {
11119  IAElement = InactiveTrackElementAt(86, IMPair.second);
11120  }
11121  if(IAElement.LocationName == "")
11122  {
11123 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11124  SignalPlatformGraphic = RailGraphics->gl79Striped;
11125  }
11126  else
11127  {
11128 // SignalPlatformGraphic = RailGraphics->Plat71;
11129  SignalPlatformGraphic = RailGraphics->gl79;
11130  }
11131  Utilities->CallLogPop(953);
11132  return(true);
11133  }
11134  }
11135  Utilities->CallLogPop(954);
11136  return(false);
11137 }
11138 
11139 // ---------------------------------------------------------------------------
11140 
11141 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
11142 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
11143 // false if not, if NextPos == -1, or if only own train on the track
11144 {
11145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
11146  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
11147  if(NextEntryPos < 0)
11148  {
11149  Utilities->CallLogPop(1348);
11150  return(false);
11151  }
11152  TTrackElement TrackElement = TrackElementAt(713, NextPos);
11153 
11154  if(TrackElement.TrackType != Bridge)
11155  {
11156  Utilities->CallLogPop(1349);
11157  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11158  }
11159 // bridge if reach here
11160  if(NextEntryPos > 1)
11161  {
11162  Utilities->CallLogPop(1350);
11163  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11164  }
11165  else
11166  {
11167  Utilities->CallLogPop(1351);
11168  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11169  }
11170 }
11171 
11172 // ---------------------------------------------------------------------------
11173 
11175 {
11176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11177  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11178  {
11179  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11180  }
11181  Utilities->CallLogPop(1483);
11182  return(SelectVector.at(At));
11183 }
11184 
11185 // ---------------------------------------------------------------------------
11186 
11187 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11188 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11189 {
11190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11191  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11192  bool FoundFlag = false;
11193  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11194  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11195 
11196  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11197  Utilities->CallLogPop(1538);
11198  return(FoundFlag);
11199 }
11200 
11201 // ---------------------------------------------------------------------------
11202 
11203 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11204 {
11205 // return true if find an inactive element called 'Name'
11206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11207  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11208  bool FoundFlag = false;
11209 
11210  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11211  {
11212  if(InactiveTrackElementAt(158, x).LocationName == Name)
11213  {
11214  FoundFlag = true;
11215  int V = InactiveTrackElementAt(159, x).VLoc;
11216  int H = InactiveTrackElementAt(160, x).HLoc;
11217  if(V > VLocHi)
11218  {
11219  VLocHi = V;
11220  }
11221  if(V < VLocLo)
11222  {
11223  VLocLo = V;
11224  }
11225  if(H < HLoc)
11226  {
11227  HLoc = H;
11228  }
11229  }
11230  }
11231  if(FoundFlag)
11232  {
11233  VPosHi = 16 * VLocHi;
11234  VPosLo = 16 * VLocLo;
11235  HPos = 16 * HLoc;
11236  Utilities->CallLogPop(1562);
11237  return(true);
11238  }
11239  else
11240  {
11241  Utilities->CallLogPop(1563);
11242  return(false);
11243  }
11244 }
11245 
11246 // ---------------------------------------------------------------------------
11247 
11248 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11249 {
11250 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11251 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11252  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11253  AnsiString(EndTVPosition));
11254  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11255  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11256 
11257 // get H & V values for the element adjacent to Link[0] & Link[1]
11258  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11259  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11260  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11261  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11262 
11263 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11264  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11265  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11266  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11267  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11268 
11269  if(Link0Squares <= Link1Squares)
11270  {
11271  Utilities->CallLogPop(1851);
11272  return(0);
11273  }
11274  else
11275  {
11276  Utilities->CallLogPop(1852);
11277  return(1);
11278  }
11279 }
11280 
11281 // ---------------------------------------------------------------------------
11282 
11283 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11284 {
11285  // element can be points or any other type
11286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11287  AnsiString(LinkPos));
11288  Derail = false;
11289  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11290 
11291  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11292  {
11293  if(TE.Attribute == 0)
11294  {
11295  Utilities->CallLogPop(663);
11296  return(1); // Att == 0 & ExitPos == 1 represent straight
11297  }
11298  else
11299  {
11300  Utilities->CallLogPop(664);
11301  return(3); // Att == 1 & ExitPos == 3 represent diverging
11302  }
11303  }
11304  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11305  {
11306  if((LinkPos == 1) && (TE.Attribute == 0))
11307  {
11308  Utilities->CallLogPop(665);
11309  return(0); // Att == 0 represents straight
11310  }
11311  else if(LinkPos == 1)
11312  {
11313  Derail = true;
11314  Utilities->CallLogPop(666);
11315  return(0);
11316  }
11317  else if((LinkPos == 3) && (TE.Attribute == 1))
11318  {
11319  Utilities->CallLogPop(667);
11320  return(0);
11321  }
11322  else if(LinkPos == 3)
11323  {
11324  Derail = true;
11325  Utilities->CallLogPop(668);
11326  return(0);
11327  }
11328  }
11329  else if(LinkPos == 0)
11330  {
11331  Utilities->CallLogPop(669);
11332  return(1);
11333  }
11334  else if(LinkPos == 1)
11335  {
11336  Utilities->CallLogPop(670);
11337  return(0);
11338  }
11339  else if(LinkPos == 2)
11340  {
11341  Utilities->CallLogPop(671);
11342  return(3);
11343  }
11344  else if(LinkPos == 3)
11345  {
11346  Utilities->CallLogPop(672);
11347  return(2);
11348  }
11349  throw Exception("Error, failure in GetExitPos"); // should never reach here
11350 }
11351 
11352 // ----------------------------------------------------------------------------
11353 
11355 {
11356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11357  LCVector.clear();
11358  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11359  {
11360  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11361  {
11362  LCVector.push_back(x);
11363  }
11364  }
11365  Utilities->CallLogPop(1931);
11366  return;
11367 }
11368 
11369 // ---------------------------------------------------------------------------
11370 
11371 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11372 /*
11373  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11374  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11375  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11376  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11377 */
11378 {
11379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11380  AnsiString(Link));
11381  bool FoundFlag;
11382 
11383  TrainID = -1;
11384  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11385 
11386  if(!FoundFlag)
11387  {
11388  Utilities->CallLogPop(2001);
11389  return(false);
11390  }
11391  TTrackElement TE = TrackElementAt(882, VecPos);
11392 
11393  TrainID = TE.TrainIDOnElement;
11394  if(TE.TrackType == Bridge)
11395  {
11396  if(TE.TrainIDOnElement > -1)
11397  {
11398  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11399  {
11401  }
11402  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11403  {
11405  }
11406  else
11407  {
11408  TrainID = -1; // shouldn't ever reach here but be safe
11409  }
11410  }
11411  }
11412  if(TrainID == -1)
11413  {
11414  Utilities->CallLogPop(2002);
11415  return(false);
11416  }
11417 // now get the train
11418  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11419 
11420  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11421  {
11422  Utilities->CallLogPop(2003);
11423  return(true);
11424  }
11425  TrainID = -1;
11426  Utilities->CallLogPop(2004);
11427  return(false);
11428 }
11429 
11430 // ---------------------------------------------------------------------------
11431 
11432 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11433 /* New at v1.2.0
11434  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11435  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11436  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11437  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11438  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11439  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11440  Each of these is examined in turn for each route element in the relevant position.
11441 */
11442 {
11443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11444  "," + AnsiString(DiagonalLinkNumber));
11445  TrainID = -1;
11446  TPrefDirElement TempPrefDirElement;
11447  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11448 
11449  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11450  {
11451  Utilities->CallLogPop(2027);
11452  return(true);
11453  }
11454  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11455  {
11456  Utilities->CallLogPop(2028);
11457  return(true);
11458  }
11459  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11460  {
11461  Utilities->CallLogPop(2029);
11462  return(true);
11463  }
11464  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11465  {
11466  Utilities->CallLogPop(2030);
11467  return(true);
11468  }
11469  Utilities->CallLogPop(2031);
11470  return(false);
11471 }
11472 
11473 // ---------------------------------------------------------------------------
11474 
11475 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11476 {
11477  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11478  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11479  TUserGraphicItem UGI;
11480  AnsiString JustFileName = "";
11481 
11482  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11483  {
11484  UGI = UserGraphicVectorAt(17, x);
11485  int LastDelim = UGI.FileName.LastDelimiter('\\');
11486  if(LastDelim == 0) // can't find it so skip this item
11487  {
11488  continue;
11489  }
11490  else
11491  {
11492  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11493  }
11494  Utilities->SaveFileString(VecFile, JustFileName);
11495  Utilities->SaveFileInt(VecFile, UGI.HPos);
11496  Utilities->SaveFileInt(VecFile, UGI.VPos);
11497  }
11498  Utilities->CallLogPop(2178);
11499 }
11500 
11501 // ---------------------------------------------------------------------------
11502 
11503 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11504 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11505 {
11506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11507  int NumPlats = 0;
11508  TTrackElement TempElement;
11509  int TempInt;
11510 
11511  typedef std::list<int> TNamePosList;
11512  TNamePosList NamePosList;
11513  typedef TNamePosList::iterator TNPLIt;
11514  TNPLIt NPLIt;
11515  typedef std::list<int> TOnePlatList;
11516  TOnePlatList OnePlatList;
11517  typedef TOnePlatList::iterator TOPLIt;
11518  TOPLIt OPLIt;
11519 
11520  NamePosList.clear();
11521  OnePlatList.clear();
11522  for(unsigned int x = 0; x < TrackVector.size(); x++)
11523  {
11524  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11525  {
11526  NamePosList.push_back(x);
11527  }
11528  }
11529  //NamePosList complete
11530 
11531  if(!NamePosList.empty()) //first value for the loop examination
11532  {
11533  OnePlatList.push_back(NamePosList.back());
11534  NamePosList.pop_back(); //erase from NPV as done with it here
11535  }
11536  while(!OnePlatList.empty()) //loop to examine all linked elements
11537  {
11538  TempInt = OnePlatList.front();
11539  TempElement = TrackElementAt(989, TempInt);
11540 
11541  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11542  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11543  {
11544  OnePlatList.push_back(TempElement.Conn[0]);
11545  NamePosList.erase(NPLIt);
11546  }
11547  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11548  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11549  {
11550  OnePlatList.push_back(TempElement.Conn[1]);
11551  NamePosList.erase(NPLIt);
11552  }
11553  //here when loaded any connecting links into OnePlatList, so can erase the front element
11554  OnePlatList.erase(OnePlatList.begin());
11555  if(OnePlatList.empty())
11556  {
11557  NumPlats++; //finished with current linked elements so can increment NumPlats
11558  if(!NamePosList.empty())
11559  {
11560  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11561  NamePosList.pop_back(); //erase from NPV as done with it there
11562  }
11563  }
11564  }
11565  Utilities->CallLogPop(2218);
11566  return(NumPlats);
11567 }
11568 
11569 // ---------------------------------------------------------------------------
11570 
11571 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11572 {//repair Signals pointed to by FPVIt
11573  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
11574  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
11575  if(TE.TrackType != SignalPost)
11576  {
11577  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
11578  }
11579  if(!TE.Failed)
11580  {
11581  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
11582  }
11583  TE.Failed = false;
11584  //set to correct aspect
11585  int RouteNumber;
11586  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
11587  { // 0 for LinkPos ok as a signal so only one track
11588  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
11589  }
11590  //erase from vector
11591  Track->FailedSignalsVector.erase(FPVIt);
11592 
11593  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11594  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11595  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
11596  AllRoutes->RebuildRailwayFlag = true;
11597  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
11598  Utilities->CallLogPop(2519);
11599 }
11600 
11601 // ---------------------------------------------------------------------------
11602 
11603 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11604 {//repair points pointed to by FPVIt
11605  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
11606  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
11607  if(TE.TrackType != Points)
11608  {
11609  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
11610  }
11611  if(!TE.Failed)
11612  {
11613  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
11614  }
11615  TE.Failed = false;
11620  //erase from vector
11621  Track->FailedPointsVector.erase(FPVIt);
11622 
11623  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11624  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11625  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
11626  AllRoutes->RebuildRailwayFlag = true;
11627  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11628  Utilities->CallLogPop(2518);
11629 }
11630 
11631 // ---------------------------------------------------------------------------
11632 
11633 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11634 {//repair TSR pointed to by FPVIt
11635  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
11636  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
11637  if(TE.TrackType != Simple)
11638  {
11639  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
11640  }
11641  if(!TE.Failed)
11642  {
11643  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
11644  }
11645  TE.Failed = false;
11648  //erase from vector
11649  Track->TSRVector.erase(FPVIt);
11650 
11651  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11652  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11653  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
11654  AllRoutes->RebuildRailwayFlag = true;
11655  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11656  Utilities->CallLogPop(2520);
11657 }
11658 
11659 // ---------------------------------------------------------------------------
11660 
11662 {
11663  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
11664  SimpleVector.clear();
11665  for(unsigned int x = 0; x < TrackVector.size(); x++)
11666  {
11667  if(TrackElementAt(1517, x).TrackType == Simple)
11668  {
11669  SimpleVector.push_back(int(x));
11670  }
11671  }
11672  Utilities->CallLogPop(2521);
11673 }
11674 
11675 // ---------------------------------------------------------------------------
11676 // UserGraphic, PrefDir & Route functions
11677 // ---------------------------------------------------------------------------
11678 
11680 {
11681  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11682  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11683  {
11684  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11685  }
11686  Utilities->CallLogPop(2194);
11687  return(UserGraphicVector.at(At));
11688 }
11689 
11690 // ---------------------------------------------------------------------------
11691 
11692 int TOnePrefDir::LastElementNumber(int Caller) const
11693 {
11694  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11695  int RetVal = PrefDirVector.size() - 1;
11696 
11697  if(RetVal < 0)
11698  {
11699  throw Exception("Return value negative in call to LastElementNumber");
11700  }
11701  Utilities->CallLogPop(114);
11702  return(RetVal);
11703 }
11704 
11705 // ---------------------------------------------------------------------------
11707 {
11708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11709  if(PrefDirVector.empty())
11710  {
11711  throw Exception("PrefDirVector empty in call to LastElementPtr");
11712  }
11713  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11714 
11715  Utilities->CallLogPop(115);
11716  return(RetIT);
11717 }
11718 
11719 // ---------------------------------------------------------------------------
11721 {
11722  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11723  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11724  {
11725  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11726  }
11727  Utilities->CallLogPop(116);
11728  return(PrefDirVector.at(At));
11729 }
11730 
11731 // ---------------------------------------------------------------------------
11733 {
11734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11735  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11736  {
11737  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11738  " in GetModifiablePrefDirElementAt");
11739  }
11740  Utilities->CallLogPop(117);
11741  return(PrefDirVector.at(At));
11742 }
11743 
11744 // ---------------------------------------------------------------------------
11746 {
11747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11748  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11749  {
11750  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11751  }
11752  Utilities->CallLogPop(118);
11753  return(SearchVector.at(At));
11754 }
11755 
11756 // ---------------------------------------------------------------------------
11758 {
11759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11760  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11761  {
11762  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11763  }
11764  Utilities->CallLogPop(119);
11765  return(SearchVector.at(At));
11766 }
11767 
11768 // ---------------------------------------------------------------------------
11769 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11770 /*
11771  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11772  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11773  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11774  set in later functions.
11775 */
11776 {
11777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11778  ClearPrefDir();
11779  int TrackVectorPosition;
11780  TTrackElement TrackElement;
11781 
11782  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11783  {
11784  Utilities->CallLogPop(126);
11785  return(false);
11786  }
11787 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11788  if(TrackElement.TrackType == Points)
11789  {
11790  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11791  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11792  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11793  //best to prevent it to avoid problems
11794  Utilities->CallLogPop(127);
11795  return false;
11796  }
11797 */
11798  TPrefDirElement PrefDirElement(TrackElement);
11799 
11800  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11801  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11802  StorePrefDirElement(1, PrefDirElement); // enter first element
11803 // Note that ELink not set even if a buffer or continuation - these set in
11804 // ConvertPrefDirSearchVector after 2nd element added
11805 
11806  Utilities->CallLogPop(128);
11807  return(true);
11808 }
11809 
11810 // ---------------------------------------------------------------------------
11811 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11812 
11813 /*
11814  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11815  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
11816  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11817  with setting the PrefDir vector, & return true.
11818  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11819  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
11820  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11821  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11822  ConvertPrefDirSearchVector to set PrefDirVector.
11823  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11824  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11825  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11826 */
11827 
11828 {
11829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11830  FinishElement = false;
11831  int TrackVectorPosition;
11832 
11833  TotalSearchCount = 0;
11834  TTrackElement TrackElement, TempTrackElement;
11835 
11836  if(PrefDirVector.size() == 0)
11837  {
11838  Utilities->CallLogPop(129);
11839  return(false);
11840  }
11841  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11842  {
11843  Utilities->CallLogPop(130);
11844  return(false);
11845  }
11846 // set the search limits using the last stored element in PrefDirVector as the start point
11847 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11848 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11849 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11850 
11851  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11852 
11853  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11854  {
11855  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11856  SearchLimitHighH = TrackElement.HLoc + 15;
11857  }
11858  else
11859  {
11860  SearchLimitLowH = TrackElement.HLoc - 15;
11861  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11862  }
11863  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11864  {
11865  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11866  SearchLimitHighV = TrackElement.VLoc + 15;
11867  }
11868  else
11869  {
11870  SearchLimitLowV = TrackElement.VLoc - 15;
11871  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11872  }
11873 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11874  check & TotalSearchCounts check
11875  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11876  {
11877  ShowMessage("Unable to reach the selected element - too far ahead");
11878  Utilities->CallLogPop(1692);
11879  return false;
11880  }
11881 */
11882 // get last PrefDir element
11883  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11884  {
11885  // check if TrackElement adjacent to any of the 4 XLinkPos'
11886  for(int x = 0; x < 4; x++)
11887  {
11888  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11889  {
11890  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11891  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11892  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11893  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11894  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11895  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11896  // shouldn't ever get it in a serious railway though.
11897 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11898  }
11899  }
11900  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11901  {
11902  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11903  SearchVector.clear(); // use this & convert to set all PrefDir element values
11904  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11905  {
11907  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11908  {
11909  FinishElement = true;
11910  }
11911  Utilities->CallLogPop(131);
11912  return(true);
11913  }
11914  } // not an adjacent element
11915 
11916  // now check each of the 4 possible XLinkPos values
11917  for(int x = 0; x < 4; x++)
11918  {
11919  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11920  {
11921  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11922  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11923  SearchVector.clear();
11924  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11925  {
11927  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11928  {
11929  FinishElement = true;
11930  }
11931  Utilities->CallLogPop(132);
11932  return(true);
11933  }
11934  }
11935  } // here if checked all possible exits without success
11936  ShowMessage(
11937  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11938  Utilities->CallLogPop(133);
11939  return(false);
11940  }
11941 // dealt above with LastPrefDirElement being the start element (which can be points)
11942 
11943  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11944  .ELinkPos] == Lead)) // leading point
11945  {
11946  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11947  {
11948  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11949  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11950  // can't be buffers or gap if points
11951  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11952  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11953  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11954  SearchVector.clear();
11955  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11956  {
11958  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11959  {
11960  FinishElement = true;
11961  }
11962  Utilities->CallLogPop(134);
11963  return(true);
11964  }
11965  }
11966  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11967  {
11968  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11969  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11970  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11971  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11972  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11973  SearchVector.clear();
11974  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11975  {
11977  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11978  {
11979  FinishElement = true;
11980  }
11981  Utilities->CallLogPop(135);
11982  return(true);
11983  }
11984  }
11985 // above dealt with immediate finds for leading point,
11986 // now deal with ordinary searches for leading point
11987  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11988  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11989  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11990  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11991  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11992  SearchVector.clear();
11993  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11994  {
11996  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11997  {
11998  FinishElement = true;
11999  }
12000  Utilities->CallLogPop(136);
12001  return(true);
12002  }
12003  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12004  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12005  // note that CheckCount already increased to allow for XLinkPos & XLink
12006  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12007  SearchVector.clear();
12008  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12009  {
12011  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12012  {
12013  FinishElement = true;
12014  }
12015  Utilities->CallLogPop(137);
12016  return(true);
12017  }
12018 // here if failed to find match for leading point
12019  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12020  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12021  ShowMessage(
12022  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12023  Utilities->CallLogPop(138);
12024  return(false);
12025  }
12026 // leading point fully dealt with above
12027 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12028 // separately as covered in ordinary search.
12029 
12030  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12031  SearchVector.clear();
12032 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12033  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12034  {
12036  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12037  {
12038  FinishElement = true;
12039  }
12040  Utilities->CallLogPop(139);
12041  return(true);
12042  }
12043  ShowMessage(
12044  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12045  Utilities->CallLogPop(140);
12046  return(false); // failed to find required element
12047 }
12048 
12049 // ---------------------------------------------------------------------------
12050 
12051 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12052 /*
12053  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12054  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12055  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12056  Keep a count of entries in SearchVector during the current function call, so that this number can be
12057  erased for an unproductive branch search.
12058  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12059  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12060  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12061  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12062  If not any of above, store element in searchvector, set the new current element values from the
12063  SearchElement, then go back to the while loop for the next step in the search.
12064 */
12065 {
12066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12067  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12068  int VectorCount = 0;
12069 
12070  while(true)
12071  {
12072  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12073  {
12074  for(int x = 0; x < VectorCount; x++)
12075  {
12076  SearchVector.erase(SearchVector.end() - 1);
12077  }
12078  Utilities->CallLogPop(141);
12079  return(false);
12080  }
12081  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12082  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12083  TPrefDirElement SearchElement(NextTrackElement);
12084  SearchElement.TrackVectorPosition = NextPosition;
12085  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12086  SearchElement.ELinkPos = NextELinkPos;
12087  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12088  int NextXLinkPos;
12089  if(SearchElement.ELinkPos == 0)
12090  {
12091  NextXLinkPos = 1;
12092  }
12093  if(SearchElement.ELinkPos == 1)
12094  {
12095  NextXLinkPos = 0;
12096  }
12097  if(SearchElement.ELinkPos == 2)
12098  {
12099  NextXLinkPos = 3;
12100  }
12101  if(SearchElement.ELinkPos == 3)
12102  {
12103  NextXLinkPos = 2;
12104  }
12105  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12106  {
12107  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12108  // but may be buffers, continuation or gap
12109  SearchElement.XLinkPos = NextXLinkPos;
12110  }
12111 // can't set XLink or XLinkPos yet if the element is a leading point.
12112 // check if found it
12113  if(SearchElement.TrackVectorPosition == RequiredPosition)
12114  {
12115  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12116  VectorCount++; // not really needed but include for tidyness
12117  TotalSearchCount++;
12118  Utilities->CallLogPop(142);
12119  return(true);
12120  }
12121 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12122 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12123 // at a time - drop this
12124 /*
12125  if(PrefDirVector.size() > 200)
12126  {
12127  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12128  Utilities->CallLogPop(1419);
12129  return false;
12130  }
12131 */
12132 // check if a buffer or continuation
12133  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12134  {
12135  for(int x = 0; x < VectorCount; x++)
12136  {
12137  SearchVector.erase(SearchVector.end() - 1);
12138  }
12139  Utilities->CallLogPop(143);
12140  return(false);
12141  }
12142 // check if reached an earlier position on search PrefDir with same entry value
12143  for(unsigned int x = 0; x < SearchVector.size(); x++)
12144  {
12145  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12146  {
12147  for(int x = 0; x < VectorCount; x++)
12148  {
12149  SearchVector.erase(SearchVector.end() - 1);
12150  }
12151  Utilities->CallLogPop(144);
12152  return(false);
12153  }
12154  }
12155 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12156 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12157  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12158  {
12159  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12160  {
12161  for(int x = 0; x < VectorCount; x++)
12162  {
12163  SearchVector.erase(SearchVector.end() - 1);
12164  }
12165  Utilities->CallLogPop(1417);
12166  return(false);
12167  }
12168  }
12169 
12170 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12171 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12172 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12174  {
12175  for(int x = 0; x < VectorCount; x++)
12176  {
12177  SearchVector.erase(SearchVector.end() - 1);
12178  }
12179  Utilities->CallLogPop(1691);
12180  return(false);
12181  }
12182 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12183  if(SearchVector.size() > 150)
12184  {
12185  for(int x = 0; x < VectorCount; x++)
12186  {
12187  SearchVector.erase(SearchVector.end() - 1);
12188  }
12189  Utilities->CallLogPop(1418);
12190  return(false);
12191  }
12192 // check if reached a leading point
12193  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12194  {
12195 // push element with XLink set to position [1]
12196  SearchElement.XLink = SearchElement.Link[1];
12197  SearchElement.XLinkPos = 1;
12198  SearchVector.push_back(SearchElement);
12199  VectorCount++;
12200  TotalSearchCount++;
12201  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12202  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12203  // can't be used. NextTrackElement is the corresponding TTrackElement.
12204  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12205  {
12206  Utilities->CallLogPop(145);
12207  return(true);
12208  }
12209  else
12210  {
12211 // remove leading point with XLinkPos [1]
12212  SearchVector.erase(SearchVector.end() - 1);
12213  VectorCount--;
12214 // push element with XLink set to position [3]
12215  SearchElement.XLink = SearchElement.Link[3];
12216  SearchElement.XLinkPos = 3;
12217  SearchVector.push_back(SearchElement);
12218  VectorCount++;
12219  TotalSearchCount++;
12220 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12221  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12222  {
12223  Utilities->CallLogPop(146);
12224  return(true);
12225  }
12226  else
12227  {
12228  for(int x = 0; x < VectorCount; x++)
12229  {
12230  SearchVector.erase(SearchVector.end() - 1);
12231  }
12232  Utilities->CallLogPop(147);
12233  return(false);
12234  }
12235  }
12236  } // if leading point
12237 
12238 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12239 // ready for next element on PrefDir
12240  SearchVector.push_back(SearchElement);
12241  VectorCount++;
12242  TotalSearchCount++;
12243  XLinkPos = NextXLinkPos;
12244  CurrentTrackElement = SearchElement;
12245  } // while(true)
12246 }
12247 
12248 // ---------------------------------------------------------------------------
12249 
12251 /*
12252  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12253  for each element on the search PrefDir, though if the last element is a leading point
12254  then the final XLink won't be set.
12255  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12256  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12257  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12258 */
12259 {
12260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12261  if(SearchVector.size() == 0)
12262  {
12263  throw Exception("Error, SearchVector empty");
12264  }
12265 // get first SearchElement in order to set last PrefDirelement
12266  TPrefDirElement SearchElement = SearchVector.at(0);
12267 
12268 // set last PrefDir element XLink & ELink values if not already set
12269 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12270  for(int x = 0; x < 4; x++)
12271  {
12272  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12273  {
12274  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12275  {
12276  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12277  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12278  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12279  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12280  }
12281  int ELinkPos;
12282  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12283  {
12284  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12285  }
12286  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12287  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12288  {
12289  ELinkPos = 0;
12290  }
12291  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12292  {
12293  ELinkPos = 3;
12294  }
12295  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12296  {
12297  ELinkPos = 2;
12298  }
12299  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12300  {
12301  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12302  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12303  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12304  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12305  }
12306  break; // no point going any further
12307  }
12308  }
12309 // set EXNumber for last PrefDir element, unless already set
12310 // won't be set if was first element or a leading point
12311  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12312  {
12313 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12314  int EXArray[32][2] = {
12315  {4,6},{2,8}, //horizontal & vertical
12316  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12317  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12318  {1,9},{3,7} //forward & reverse diagonals
12319 */
12320 
12321  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12322  {
12323  throw Exception("Error in EntryExitNumber 1");
12324  }
12325  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12326  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12327  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12328  }
12329 // Last PrefDir element now complete
12330 
12331 // construct remaining PrefDir elements from searchvector
12332  for(unsigned int x = 0; x < SearchVector.size(); x++)
12333  {
12334  SearchElement = SearchVector.at(x);
12335  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12336  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12337  PrefDirElement.ELink = SearchElement.ELink;
12338  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12339  PrefDirElement.XLink = SearchElement.XLink;
12340  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12341 // if XLink & XLinkPos not set don't account for them in CheckCount
12342  if(PrefDirElement.XLink == -1)
12343  {
12344  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12345  }
12346  // & TrackVectorPosition
12347  else
12348  {
12349  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12350  }
12351  // XLink, XLinkPos, TrackVectorPosition
12352 
12353 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12354  if(PrefDirElement.XLink != -1)
12355  {
12356  if(!(PrefDirElement.EntryExitNumber()))
12357  {
12358  throw Exception("Error in EntryExitNumber 2");
12359  }
12360  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12361  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12362  PrefDirElement.CheckCount++;
12363  // all values now incorporated if not a leading point
12364  }
12365 // store PrefDir element
12366  StorePrefDirElement(2, PrefDirElement);
12367  }
12368 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12369  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12370  {
12371  if(ValidatePrefDir(2))
12372  {
12373  ;
12374  } // error messages given within function
12375 
12376  }
12378 /* drop this, check dropped from search
12379  if(PrefDirVector.size() > 200)
12380  {
12381  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12382  }
12383 */
12384  Utilities->CallLogPop(148);
12385 }
12386 
12387 // ---------------------------------------------------------------------------
12388 
12389 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12390 /*
12391  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12392  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12393 */
12394 {
12395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12396  LeadingPoints = false;
12397  if(PrefDirVector.empty())
12398  {
12399  Utilities->CallLogPop(1786);
12400  return(false); // should never be empty but allow for it for safety
12401  }
12402  if(PrefDirVector.size() == 1)
12403  {
12404  Utilities->CallLogPop(149);
12405  return(false); // can't end if only one element
12406  }
12407 /*
12408  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12409  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12410  {
12411  Utilities->CallLogPop(150);
12412  return true;
12413  }
12414 */
12415 // allow for anything but leading points
12416  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12417  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12418  {
12419  Utilities->CallLogPop(1776);
12420  return(true);
12421  }
12422  else
12423  {
12424  LeadingPoints = true;
12425  Utilities->CallLogPop(151);
12426  return(false);
12427  }
12428 }
12429 
12430 // ---------------------------------------------------------------------------
12431 
12433 /*
12434  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12435  and that every element is connected to the next element
12436 */
12437 {
12438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12439  int Position;
12440  AnsiString ErrorString;
12441  bool Error = false;
12442 
12443  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12444  {
12445  if(PrefDirVector.at(x).HLoc == -2000000000)
12446  {
12447  Error = true;
12448  ErrorString = "HLoc";
12449  Position = x;
12450  }
12451  if(PrefDirVector.at(x).VLoc == -2000000000)
12452  {
12453  Error = true;
12454  ErrorString = "VLoc";
12455  Position = x;
12456  }
12457  if(PrefDirVector.at(x).ELink == -1)
12458  {
12459  Error = true;
12460  ErrorString = "ELink";
12461  Position = x;
12462  }
12463  if(PrefDirVector.at(x).ELinkPos == -1)
12464  {
12465  Error = true;
12466  ErrorString = "ELinkPos";
12467  Position = x;
12468  }
12469  if(PrefDirVector.at(x).XLink == -1)
12470  {
12471  Error = true;
12472  ErrorString = "XLink";
12473  Position = x;
12474  }
12475  if(PrefDirVector.at(x).XLinkPos == -1)
12476  {
12477  Error = true;
12478  ErrorString = "XLinkPos";
12479  Position = x;
12480  }
12481  if(PrefDirVector.at(x).SpeedTag == 0)
12482  {
12483  Error = true;
12484  ErrorString = "Tag";
12485  Position = x;
12486  }
12487  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12488  {
12489  Error = true;
12490  ErrorString = "TrackVectorPosition";
12491  Position = x;
12492  }
12493  if(PrefDirVector.at(x).EXNumber == -1)
12494  {
12495  Error = true;
12496  ErrorString = "EXNumber";
12497  Position = x;
12498  }
12499  if(PrefDirVector.at(x).CheckCount != 9)
12500  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12501  {
12502  Error = true;
12503  ErrorString = "CheckCount";
12504  Position = x;
12505  }
12506 // extra checks
12507  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12508  {
12509  Error = true;
12510  ErrorString = "EntryGraphicPtr";
12511  Position = x;
12512  }
12513  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12514  {
12515  Error = true;
12516  ErrorString = "EntryDirectionGraphicPtr";
12517  Position = x;
12518  }
12519 // end of extra checks
12520  if(x > 0)
12521  {
12522  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12523  {
12524  Error = true;
12525  ErrorString = "Last XLink not connected to this element";
12526  Position = x;
12527  }
12528  }
12529  }
12530  if(Error)
12531  {
12532  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12533  }
12534  else
12535  {
12536  Utilities->CallLogPop(153);
12537  return(true);
12538  }
12539 }
12540 
12541 // ---------------------------------------------------------------------------
12542 
12543 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12544 /*
12545  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12546  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12547  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12548  or a leading point.
12549 */
12550 {
12551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12552  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12553  {
12554  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12555  {
12556  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12557  {
12558  ErasePrefDirElementAt(1, PrefDirVecPos);
12559  }
12560  if(PrefDirVector.size() == 0)
12561  {
12562  Utilities->CallLogPop(154);
12563  return(true);
12564  }
12565  if(PrefDirVector.size() == 1)
12566  {
12567  PrefDirVector.at(x - 1).ELinkPos = -1;
12568  PrefDirVector.at(x - 1).ELink = -1;
12569  PrefDirVector.at(x - 1).XLinkPos = -1;
12570  PrefDirVector.at(x - 1).XLink = -1;
12571  PrefDirVector.at(x - 1).EXNumber = -1;
12572  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12573  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12574  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12575  Utilities->CallLogPop(155);
12576  return(true);
12577  }
12578  // here with truncate element not first element, so ELink & ELinkPos set
12579  // unset XLink & Pos if a leading point
12580  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12581  {
12582  PrefDirVector.at(x - 1).XLinkPos = -1;
12583  PrefDirVector.at(x - 1).XLink = -1;
12584  PrefDirVector.at(x - 1).EXNumber = -1;
12585  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12586  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12587  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12588  Utilities->CallLogPop(156);
12589  return(true);
12590  }
12591  Utilities->CallLogPop(157);
12592  return(true);
12593  }
12594  }
12595  Utilities->CallLogPop(158);
12596  return(false);
12597 }
12598 
12599 // ---------------------------------------------------------------------------
12600 
12601 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12602 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12603 /*
12604  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12605  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12606  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12607  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12608  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12609  displayed.
12610 */
12611 {
12612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12613  AnsiString((short)BuildingPrefDir));
12614  int HPos, VPos;
12615 
12616  if(PrefDirSize() == 0)
12617  {
12618  Utilities->CallLogPop(159);
12619  return;
12620  }
12621  for(unsigned int x = 0; x < PrefDirSize(); x++)
12622  {
12623  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12624 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12625 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12626 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12627  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12628  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12629  // only the front half of which will be overplotted by the back of the train, then when the train is
12630  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12631  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12632  {
12633  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12634  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12635  {
12636  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12637  }
12638  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12639  // Route, no direction if a single element
12640  {
12641  if(x == 0)
12642  {
12643  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12644  }
12645  if(x == (PrefDirSize() - 1))
12646  {
12647  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12648  }
12649  }
12650  }
12651  }
12652 
12653 // set start & end element colours if building a PrefDir
12654  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12655  {
12656  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12657  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12658  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12659  // set last element colour
12660  if(PrefDirSize() > 1)
12661  {
12662  unsigned int LatestPos = PrefDirSize() - 1;
12663  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12664  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12665  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12666  }
12667  }
12668  Disp->Update();
12669  Utilities->CallLogPop(160);
12670 }
12671 
12672 // ---------------------------------------------------------------------------
12673 
12675 /*
12676  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12677  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12678 */
12679 {
12680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12681  if(PrefDirSize() == 0)
12682  {
12683  Utilities->CallLogPop(1547);
12684  return;
12685  }
12686  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12687  bool FoundFlag;
12689  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12690 
12691  while(MMIT != PrefDir4MultiMap.end())
12692  {
12693  H = MMIT->first.first;
12694  V = MMIT->first.second;
12695  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12696  // always found in order, any missing have PrefDirPosx == -1
12697  if(PrefDirPos0 > -1)
12698  {
12699  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12700  }
12701  if(PrefDirPos1 > -1)
12702  {
12703  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12704  }
12705  if(PrefDirPos2 > -1)
12706  {
12707  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12708  }
12709  if(PrefDirPos3 > -1)
12710  {
12711  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12712  }
12713  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12714  {
12715  // need to plot all 4 in order to obtain all the direction graphics
12716  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12717  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12718  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12719  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12720  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12721  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12722  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12723  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12724  MMIT++;
12725  MMIT++;
12726  MMIT++;
12727  MMIT++;
12728  }
12729  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12730  {
12731  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12732  {
12733  // 0 & 1 constitute the bidirectional PrefDir
12734  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12735  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12736  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12737  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12738  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12739  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12740  MMIT++;
12741  MMIT++;
12742  MMIT++;
12743  }
12744  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12745  {
12746  // 0 & 2 constitute the bidirectional PrefDir
12747  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12748  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12749  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12750  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12751  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12752  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12753  MMIT++;
12754  MMIT++;
12755  MMIT++;
12756  }
12757  else
12758  {
12759  // 1 & 2 constitute the bidirectional PrefDir
12760  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12761  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12762  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12763  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12764  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12765  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12766  MMIT++;
12767  MMIT++;
12768  MMIT++;
12769  }
12770  }
12771  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12772  {
12773  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12774  {
12775  // 0 & 1 constitute the bidirectional PrefDir
12776  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12777  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12778  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12779  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12780  MMIT++;
12781  MMIT++;
12782  }
12783  else
12784  {
12785  // 2 unidirectional PrefDirs
12786  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12787  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12788  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12789  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12790  MMIT++;
12791  MMIT++;
12792  }
12793  }
12794  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12795  {
12796  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12797  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12798  MMIT++;
12799  }
12800  }
12801  Disp->Update();
12802  Utilities->CallLogPop(1548);
12803 }
12804 
12805 // ---------------------------------------------------------------------------
12806 
12807 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12808 {
12809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12810  int TempInt;
12811 
12812  ClearPrefDir();
12813  int NumberOfPrefDirElements = 0;
12814 
12815  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12816  for(int x = 0; x < NumberOfPrefDirElements; x++)
12817  {
12818  VecFile >> TempInt; // TrackVectorPosition
12819  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12820  LoadPrefDirElement.TrackVectorPosition = TempInt;
12821  VecFile >> TempInt;
12822  LoadPrefDirElement.ELink = TempInt;
12823  VecFile >> TempInt;
12824  LoadPrefDirElement.ELinkPos = TempInt;
12825  VecFile >> TempInt;
12826  LoadPrefDirElement.XLink = TempInt;
12827  VecFile >> TempInt;
12828  LoadPrefDirElement.XLinkPos = TempInt;
12829  VecFile >> TempInt;
12830  LoadPrefDirElement.EXNumber = TempInt;
12831  VecFile >> TempInt;
12832  LoadPrefDirElement.CheckCount = TempInt;
12833  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12834  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12835  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12836  if(!(LoadPrefDirElement.IsARoute))
12837  {
12838  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12839  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12840  }
12841  else
12842  {
12843  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12844  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12845  LoadPrefDirElement.PrefDirRoute);
12846  }
12847  StorePrefDirElement(5, LoadPrefDirElement);
12848  Utilities->LoadFileString(VecFile); // marker
12849  }
12851  Utilities->CallLogPop(161);
12852 }
12853 
12854 // ---------------------------------------------------------------------------
12855 
12856 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12857 {
12858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12859  int TempInt;
12860 
12861  ClearPrefDir();
12862  int NumberOfPrefDirElements = 0;
12863 
12864  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12865  for(int x = 0; x < NumberOfPrefDirElements; x++)
12866  {
12867  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12868  VecFile >> TempInt; // TrackVectorPosition
12869  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12870  LoadPrefDirElement.TrackVectorPosition = TempInt;
12871  VecFile >> TempInt;
12872  LoadPrefDirElement.ELink = TempInt;
12873  VecFile >> TempInt;
12874  LoadPrefDirElement.ELinkPos = TempInt;
12875  VecFile >> TempInt;
12876  LoadPrefDirElement.XLink = TempInt;
12877  VecFile >> TempInt;
12878  LoadPrefDirElement.XLinkPos = TempInt;
12879  VecFile >> TempInt;
12880  LoadPrefDirElement.EXNumber = TempInt;
12881  VecFile >> TempInt;
12882  LoadPrefDirElement.CheckCount = TempInt;
12883  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12884  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12885  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12886  if(!(LoadPrefDirElement.IsARoute))
12887  {
12888  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12889  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12890  }
12891  else
12892  {
12893  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12894  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12895  LoadPrefDirElement.PrefDirRoute);
12896  }
12897  StorePrefDirElement(0, LoadPrefDirElement);
12898  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12899  }
12901  Utilities->CallLogPop(1509);
12902 }
12903 
12904 // ---------------------------------------------------------------------------
12905 
12906 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12907 /*
12908  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12909  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12910 */
12911 {
12912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12913  int TempInt;
12914  int NumberOfPrefDirElements = 0;
12915 
12916  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12917  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12918  {
12919  Utilities->CallLogPop(1152);
12920  return(false);
12921  }
12922  for(int x = 0; x < NumberOfPrefDirElements; x++)
12923  {
12924  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12925  {
12926  Utilities->CallLogPop(1766);
12927  return(false);
12928  }
12929  VecFile >> TempInt;
12930  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12931  {
12932  Utilities->CallLogPop(163);
12933  return(false);
12934  }
12935  VecFile >> TempInt;
12936  if((TempInt < -1) || (TempInt > 9)) // ELink
12937  {
12938  Utilities->CallLogPop(162);
12939  return(false);
12940  }
12941  VecFile >> TempInt;
12942  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12943  {
12944  Utilities->CallLogPop(164);
12945  return(false);
12946  }
12947  VecFile >> TempInt;
12948  if((TempInt < -1) || (TempInt > 9)) // XLink
12949  {
12950  Utilities->CallLogPop(165);
12951  return(false);
12952  }
12953  VecFile >> TempInt;
12954  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12955  {
12956  Utilities->CallLogPop(166);
12957  return(false);
12958  }
12959  VecFile >> TempInt;
12960  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12961  {
12962  Utilities->CallLogPop(167);
12963  return(false);
12964  }
12965  VecFile >> TempInt;
12966  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12967  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12968  // ELinkPos, XLink, XLinkPos & EXNumber
12969  {
12970  Utilities->CallLogPop(168);
12971  return(false);
12972  }
12973  VecFile >> TempInt;
12974  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12975  {
12976  Utilities->CallLogPop(1147);
12977  return(false);
12978  }
12979  VecFile >> TempInt;
12980  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12981  {
12982  Utilities->CallLogPop(1510);
12983  return(false);
12984  }
12985  VecFile >> TempInt;
12986  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12987  {
12988  Utilities->CallLogPop(1148);
12989  return(false);
12990  }
12991  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12992  {
12993  Utilities->CallLogPop(1700);
12994  return(false);
12995  }
12996  }
12997  Utilities->CallLogPop(169);
12998  return(true);
12999 }
13000 
13001 // ---------------------------------------------------------------------------
13002 
13003 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13004 {
13005  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13006  int NumberOfPrefDirElements = PrefDirVector.size();
13007 
13008  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13009  for(int y = 0; y < NumberOfPrefDirElements; y++)
13010  {
13011  VecFile << y << '\n'; // extra
13012  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13013  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13014  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13015  VecFile << PrefDirVector.at(y).XLink << '\n';
13016  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13017  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13018  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13019  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13020  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13021  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13022  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13023  {
13024  VecFile << "************" << '\0' << '\n'; // marker
13025  }
13026  else
13027  {
13028  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13029  }
13030  }
13031  Utilities->CallLogPop(170);
13032 }
13033 
13034 // ---------------------------------------------------------------------------
13035 
13036 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13037 {
13038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13039  int NumberOfSearchElements = SearchVector.size();
13040 
13041  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13042  for(int y = 0; y < NumberOfSearchElements; y++)
13043  {
13044  VecFile << y << '\n'; // extra
13045  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13046  VecFile << SearchVector.at(y).ELink << '\n';
13047  VecFile << SearchVector.at(y).ELinkPos << '\n';
13048  VecFile << SearchVector.at(y).XLink << '\n';
13049  VecFile << SearchVector.at(y).XLinkPos << '\n';
13050  VecFile << SearchVector.at(y).EXNumber << '\n';
13051  VecFile << SearchVector.at(y).CheckCount << '\n';
13052  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13053  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13054  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13055  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13056  {
13057  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13058  }
13059  else
13060  {
13061  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13062  }
13063  }
13064  Utilities->CallLogPop(1847);
13065 }
13066 
13067 // ---------------------------------------------------------------------------
13068 
13069 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13070 /*
13071  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13072  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13073 */
13074 {
13075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13076  AnsiString(VLoc));
13077  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13078 
13079  if(VecPos > -1)
13080  {
13081  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13082  }
13083  else
13084  {
13085  Utilities->CallLogPop(171);
13086  return;
13087  }
13088  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13089  if(VecPos > -1)
13090  {
13091  ErasePrefDirElementAt(3, VecPos);
13092  }
13093  else
13094  {
13095  Utilities->CallLogPop(172);
13096  return;
13097  }
13098  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13099  if(VecPos > -1)
13100  {
13101  ErasePrefDirElementAt(4, VecPos);
13102  }
13103  else
13104  {
13105  Utilities->CallLogPop(173);
13106  return;
13107  }
13108  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13109  if(VecPos > -1)
13110  {
13111  ErasePrefDirElementAt(5, VecPos);
13112  }
13113  else
13114  {
13115  Utilities->CallLogPop(174);
13116  return;
13117  }
13118  Utilities->CallLogPop(175);
13119 }
13120 
13121 // ---------------------------------------------------------------------------
13122 /*
13123  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13124  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13125 
13126  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13127  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13128  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13129  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13130  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13131  PrefDirVector to correspond to the new track layout.
13132 
13133  {
13134  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13135  if(PrefDirSize() == 0)
13136  {
13137  Utilities->CallLogPop(176);
13138  return;
13139  }
13140  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13141  {
13142  int TV = PrefDirVector.at(x).TrackVectorPosition;
13143  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13144  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13145  if(Track->BlankElementAt(0, TV))
13146  {
13147  ErasePrefDirElementAt(6, x);
13148  }
13149  //if was a blankelement at x then ConnELink and ConnXLink both -1
13150  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13151  {
13152  ErasePrefDirElementAt(7, x);
13153  }
13154  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13155  //needs to be erased once, but if don't use 'else' then will erase two elements
13156  //since 'x' will correspond to the element after the first erased element
13157  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13158  {
13159  ErasePrefDirElementAt(8, x);
13160  }
13161  }
13162  Utilities->CallLogPop(177);
13163  }
13164 */
13165 // ---------------------------------------------------------------------------
13166 
13167 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13168 /*
13169  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13170  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13171 */
13172 {
13173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13174  bool AlreadyPresent, FoundFlag;
13175  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13176 
13177  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13178  {
13179  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13180  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13181  AlreadyPresent = false;
13182  if(FoundFlag)
13183  {
13184  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13185  {
13186  AlreadyPresent = true;
13187  }
13188  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13189  {
13190  AlreadyPresent = true;
13191  }
13192  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13193  {
13194  AlreadyPresent = true;
13195  }
13196  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13197  {
13198  AlreadyPresent = true;
13199  }
13200  }
13201  if(!AlreadyPresent)
13202  {
13203  StorePrefDirElement(4, TempElement);
13204  }
13205  }
13207  Utilities->CallLogPop(178);
13208 }
13209 /* earlier brute force search
13210  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13211  {
13212  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13213  bool AlreadyPresent = false;
13214  for(unsigned int y = 0;y<PrefDirSize();y++)
13215  {
13216  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13217  }
13218  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13219  }
13220 */
13221 
13222 // ---------------------------------------------------------------------------
13223 
13225 /*
13226  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13227  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13228  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13229  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13230  positions are likely to have changed, so this function is called to reset all the necessary connections and
13231  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13232  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13233  shouldn't have changed.
13234 */
13235 {
13236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13237  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13238  {
13239  bool FoundFlag;
13240  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13241  if(FoundFlag)
13242  {
13243  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13244  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13245  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13246  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13247  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13248  for(unsigned int z = 0; z < 4; z++)
13249  {
13250  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13251  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13252  }
13253  }
13254  else
13255  {
13256  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13257  }
13258  }
13259  Utilities->CallLogPop(179);
13260 }
13261 
13262 // ---------------------------------------------------------------------------
13263 
13265 /*
13266  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13267 */
13268 {
13269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13270  bool DiscrepancyFound = false;
13271 
13272  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13273  {
13274  bool FoundFlag;
13275  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13276  if(FoundFlag)
13277  {
13278  TPrefDirElement PE = PrefDirVector.at(x);
13279  if(PE.TrackVectorPosition != VecPos)
13280  {
13281  DiscrepancyFound = true;
13282  break;
13283  }
13284  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13285  {
13286  DiscrepancyFound = true;
13287  break;
13288  }
13289  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13290  {
13291  DiscrepancyFound = true;
13292  break;
13293  }
13294  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13295  {
13296  DiscrepancyFound = true;
13297  break;
13298  }
13299  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13300  {
13301  DiscrepancyFound = true;
13302  break;
13303  }
13304  }
13305  else
13306  {
13307  DiscrepancyFound = true;
13308  }
13309  }
13310  if(DiscrepancyFound)
13311  {
13312  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13313  ClearPrefDir(); // also clears multimap
13314  }
13315  Utilities->CallLogPop(1436);
13316 }
13317 
13318 // ---------------------------------------------------------------------------
13319 
13321 /*
13322  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13323  return true for OK
13324 */
13325 {
13326  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13327  bool DiscrepancyFound = false;
13328 
13329  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13330  {
13331  bool FoundFlag;
13332  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13333  if(FoundFlag)
13334  {
13335  TPrefDirElement PE = PrefDirVector.at(x);
13336  if(PE.TrackVectorPosition != VecPos)
13337  {
13338  DiscrepancyFound = true;
13339  }
13340  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13341  {
13342  DiscrepancyFound = true;
13343  break;
13344  }
13345  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13346  {
13347  DiscrepancyFound = true;
13348  break;
13349  }
13350  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13351  {
13352  DiscrepancyFound = true;
13353  break;
13354  }
13355  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13356  {
13357  DiscrepancyFound = true;
13358  break;
13359  }
13360  }
13361  else
13362  {
13363  DiscrepancyFound = true;
13364  }
13365  }
13366  Utilities->CallLogPop(1512);
13367  return(!DiscrepancyFound);
13368 }
13369 
13370 // ---------------------------------------------------------------------------
13371 
13372 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13373 /*
13374  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13375  turn and for the overall sizes.
13376 */
13377 {
13378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13379  bool FoundFlag = false;
13380  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13381 
13382  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13383  {
13384  TPrefDirElement CheckElement = PrefDirVector.at(a);
13385  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13386  if(!FoundFlag)
13387  {
13388  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13389  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13390  }
13391  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13392  {
13393  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13394  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13395  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13396  }
13397  }
13398  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13399  {
13400  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13401  + " Caller=" + (AnsiString)Caller);
13402  }
13403  Utilities->CallLogPop(180);
13404 }
13405 
13406 // ---------------------------------------------------------------------------
13407 
13408 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13409  int &PrefDirPos3)
13410 /*
13411  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13412  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13413  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13414  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13415  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13416 */
13417 {
13418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13419  AnsiString(VLoc));
13420  THVPair PrefDirMapKeyPair;
13421 
13422  PrefDirPos0 = -1;
13423  PrefDirPos1 = -1;
13424  PrefDirPos2 = -1;
13425  PrefDirPos3 = -1;
13426  FoundFlag = false;
13427  PrefDirMapKeyPair.first = HLoc;
13428  PrefDirMapKeyPair.second = VLoc;
13429  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13430 
13431  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13432  if(ItPair.first == ItPair.second) //none found
13433  {
13434  Utilities->CallLogPop(181);
13435  return;
13436  }
13437  else
13438  {
13439  FoundFlag = true;
13440  PrefDirPos0 = ItPair.first->second;
13441  ItPair.first++;
13442  if(ItPair.first == ItPair.second)
13443  {
13444  Utilities->CallLogPop(182); //only one found
13445  return;
13446  }
13447  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13448  {
13449  PrefDirPos1 = ItPair.first->second;
13450  }
13451  ItPair.first++;
13452  if(ItPair.first == ItPair.second)
13453  {
13454  Utilities->CallLogPop(183); //2 found
13455  return;
13456  }
13457  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13458  {
13459  PrefDirPos2 = ItPair.first->second;
13460  }
13461  ItPair.first++;
13462  if(ItPair.first == ItPair.second)
13463  {
13464  Utilities->CallLogPop(184); //3 found
13465  return;
13466  }
13467  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13468  {
13469  PrefDirPos3 = ItPair.first->second; //4 found
13470  }
13471  }
13472  Utilities->CallLogPop(185);
13473 }
13474 
13475 // ---------------------------------------------------------------------------
13476 
13477 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13478 { //not used after modified the pref dir checking function at v2.13.0
13479  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13480  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13481  try
13482  {
13483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13484  + "," + AnsiString(LinkNumberPos));
13485  bool FoundFlag;
13486  int PD0, PD1, PD2, PD3;
13487  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13488  {
13489  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13490  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13491  PD0, PD1, PD2, PD3);
13492  if(!FoundFlag)
13493  {
13494  Utilities->CallLogPop(2282);
13495  return(false);
13496  }
13497  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13498  {
13499  if(PD0 > -1)
13500  {
13501  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13502  {
13503  LinkedPrefDirVectorNumber = PD0;
13504  Utilities->CallLogPop(2283);
13505  return(true);
13506  }
13507  }
13508  if(PD1 > -1)
13509  {
13510  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13511  {
13512  LinkedPrefDirVectorNumber = PD1;
13513  Utilities->CallLogPop(2284);
13514  return(true);
13515  }
13516  }
13517  }
13518  if(PD0 > -1)
13519  {
13520  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13521  {
13522  LinkedPrefDirVectorNumber = PD0;
13523  Utilities->CallLogPop(2285);
13524  return(true);
13525  }
13526  }
13527  if(PD1 > -1)
13528  {
13529  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13530  {
13531  LinkedPrefDirVectorNumber = PD1;
13532  Utilities->CallLogPop(2286);
13533  return(true);
13534  }
13535  }
13536  if(PD2 > -1)
13537  {
13538  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13539  {
13540  LinkedPrefDirVectorNumber = PD2;
13541  Utilities->CallLogPop(2287);
13542  return(true);
13543  }
13544  }
13545  if(PD3 > -1)
13546  {
13547  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13548  {
13549  LinkedPrefDirVectorNumber = PD3;
13550  Utilities->CallLogPop(2288);
13551  return(true);
13552  }
13553  }
13554  LinkedPrefDirVectorNumber = -1;
13555  Utilities->CallLogPop(2289);
13556  return(false);
13557  }
13558  else //buffer or continuation, no link at position 0 but not a failure
13559  {
13560  LinkedPrefDirVectorNumber = -1;
13561  Utilities->CallLogPop(2290);
13562  return(true);
13563  }
13564  }
13565  catch(const Exception &e) //non error catch
13566  {
13567  LinkedPrefDirVectorNumber = -1;
13568  Utilities->CallLogPop(2291);
13569  return(false);
13570  }
13571 }
13572 
13573 // ---------------------------------------------------------------------------
13574 
13575 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13576 { //not used after modified the pref dir checking function at v2.13.0
13577  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
13578  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13579  try
13580  {
13581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
13582  + "," + AnsiString(LinkNumberPos));
13583  bool FoundFlag;
13584  int PD0, PD1, PD2, PD3;
13585  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13586  {
13587  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13588  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13589  PD0, PD1, PD2, PD3);
13590  if(!FoundFlag)
13591  {
13592  Utilities->CallLogPop(2468);
13593  return(false);
13594  }
13595  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13596  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
13597  if(PD0 > -1)
13598  {
13599  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
13600  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
13601  {
13602  LinkedPrefDirVectorNumber = PD0;
13603  Utilities->CallLogPop(2469);
13604  return(true);
13605  }
13606  }
13607  if(PD1 > -1)
13608  {
13609  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
13610  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
13611  {
13612  LinkedPrefDirVectorNumber = PD1;
13613  Utilities->CallLogPop(2470);
13614  return(true);
13615  }
13616  }
13617  LinkedPrefDirVectorNumber = -1;
13618  Utilities->CallLogPop(2471);
13619  return(false);
13620  }
13621  if(PD0 > -1)
13622  {
13623  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13624  {
13625  LinkedPrefDirVectorNumber = PD0;
13626  Utilities->CallLogPop(2472);
13627  return(true);
13628  }
13629  }
13630  if(PD1 > -1)
13631  {
13632  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13633  {
13634  LinkedPrefDirVectorNumber = PD1;
13635  Utilities->CallLogPop(2473);
13636  return(true);
13637  }
13638  }
13639  if(PD2 > -1)
13640  {
13641  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13642  {
13643  LinkedPrefDirVectorNumber = PD2;
13644  Utilities->CallLogPop(2474);
13645  return(true);
13646  }
13647  }
13648  if(PD3 > -1)
13649  {
13650  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13651  {
13652  LinkedPrefDirVectorNumber = PD3;
13653  Utilities->CallLogPop(2475);
13654  return(true);
13655  }
13656  }
13657  LinkedPrefDirVectorNumber = -1;
13658  Utilities->CallLogPop(2476);
13659  return(false);
13660  }
13661  else //buffer or continuation, no link at position 0 but not a failure
13662  {
13663  LinkedPrefDirVectorNumber = -1;
13664  Utilities->CallLogPop(2477);
13665  return(true);
13666  }
13667  }
13668  catch(const Exception &e) //non error catch
13669  {
13670  LinkedPrefDirVectorNumber = -1;
13671  Utilities->CallLogPop(2478);
13672  return(false);
13673  }
13674 }
13675 
13676 // ---------------------------------------------------------------------------
13677 
13679 {
13680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13681  bool FoundFlag; //not used
13682  int PD0, PD1, PD2, PD3;
13683  //recover all PDs at the H & V of PDPtr
13684  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13685 
13686  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13687  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13688 
13689  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13690  {
13691  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13692  {
13693  Utilities->CallLogPop(2292);
13694  return(true);
13695  }
13696  }
13697  if(PD1 > -1)
13698  {
13699  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13700  {
13701  Utilities->CallLogPop(2293);
13702  return(true);
13703  }
13704  }
13705  if(PD2 > -1)
13706  {
13707  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13708  {
13709  Utilities->CallLogPop(2294);
13710  return(true);
13711  }
13712  }
13713  if(PD3 > -1)
13714  {
13715  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13716  {
13717  Utilities->CallLogPop(2295);
13718  return(true);
13719  }
13720  }
13721  Utilities->CallLogPop(2296);
13722  return(false);
13723 }
13724 
13725 // ---------------------------------------------------------------------------
13726 
13727 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13728 /*
13729  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13730 */
13731 {
13732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13733  PrefDirVector.push_back(LoadPrefDirElement);
13734  THVPair PrefDir4MultiMapKeyPair;
13735  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13736 
13737  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13738  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13739  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13740  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13741  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13742 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13743  Utilities->CallLogPop(186);
13744 }
13745 
13746 // ---------------------------------------------------------------------------
13747 
13748 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13749 /*
13750  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13751  4MultiMap if they are greater than the erased value.
13752 */
13753 {
13754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13755  bool FoundFlag;
13756 
13757  if(!PrefDirVector.empty())
13758  {
13759  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13760  if(!FoundFlag)
13761  {
13762  throw Exception("Failed to find PrefDir4MultiMap erase element");
13763  }
13764  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13765  PrefDir4MultiMap.erase(EraseIt);
13766  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13768  }
13769  Utilities->CallLogPop(187);
13770 }
13771 
13772 // ---------------------------------------------------------------------------
13773 
13774 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13775 /*
13776  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13777  4MultiMap if they are greater than the erased value.
13778 */
13779 {
13780  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13781  AnsiString(ErasedElementNumber));
13782  if(!PrefDir4MultiMap.empty())
13783  {
13784  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13785  {
13786  if(MapPtr->second > ErasedElementNumber)
13787  {
13788  MapPtr->second--;
13789  }
13790  }
13791  }
13792  Utilities->CallLogPop(1450);
13793 }
13794 
13795 // ---------------------------------------------------------------------------
13796 
13797 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13798 /*
13799  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13800  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13801  nothing is found this is an error but the error message is given in the calling function.
13802 */
13803 {
13804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13805  FoundFlag = false;
13806  if(PrefDirVectorPosition >= PrefDirVector.size())
13807  {
13808  throw Exception("PrefDirVectorPosition out of range");
13809  }
13810  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13811  THVPair PrefDir4MultiMapKeyPair;
13812 
13813  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13814  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13815  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13816 
13817  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13818  if(ItPair.first == ItPair.second)
13819  {
13820  Utilities->CallLogPop(188);
13821  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13822  }
13823  else
13824  {
13825  if(ItPair.first->second == PrefDirVectorPosition)
13826  {
13827  FoundFlag = true;
13828  Utilities->CallLogPop(189);
13829  return(ItPair.first);
13830  }
13831  ItPair.first++;
13832  if(ItPair.first == ItPair.second)
13833  {
13834  Utilities->CallLogPop(190);
13835  return(ItPair.first); // nothing found
13836  }
13837  if(ItPair.first->second == PrefDirVectorPosition)
13838  {
13839  FoundFlag = true;
13840  Utilities->CallLogPop(191);
13841  return(ItPair.first);
13842  }
13843  ItPair.first++;
13844  if(ItPair.first == ItPair.second)
13845  {
13846  Utilities->CallLogPop(192);
13847  return(ItPair.first); // nothing found
13848  }
13849  if(ItPair.first->second == PrefDirVectorPosition)
13850  {
13851  FoundFlag = true;
13852  Utilities->CallLogPop(193);
13853  return(ItPair.first);
13854  }
13855  ItPair.first++;
13856  if(ItPair.first == ItPair.second)
13857  {
13858  Utilities->CallLogPop(194);
13859  return(ItPair.first); // nothing found
13860  }
13861  if(ItPair.first->second == PrefDirVectorPosition)
13862  {
13863  FoundFlag = true;
13864  Utilities->CallLogPop(195);
13865  return(ItPair.first);
13866  }
13867  }
13868  Utilities->CallLogPop(196);
13869  return(ItPair.first); // nothing found
13870 }
13871 
13872 // ---------------------------------------------------------------------------
13873 
13874 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13875 /*
13876  Although there may be up to four entries at one H & V position this function gets just one. It is
13877  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13878  at H & V.
13879 */
13880 {
13881  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13882  THVPair PrefDir4MultiMapKeyPair;
13883 
13884  PrefDir4MultiMapKeyPair.first = HLoc;
13885  PrefDir4MultiMapKeyPair.second = VLoc;
13886  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13887 
13888  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13889  if(ItPair.first == ItPair.second) // nothing found
13890  {
13891  Utilities->CallLogPop(197);
13892  return(-1);
13893  }
13894  else
13895  {
13896  Utilities->CallLogPop(198);
13897  return(ItPair.first->second);
13898  }
13899 }
13900 
13901 // ---------------------------------------------------------------------------
13902 
13903 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13904 {
13905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13906  bool ErasedFlag = false;
13907 
13908  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13909  {
13910  if(PrefDirSize() == 0)
13911  {
13912  Utilities->CallLogPop(1511);
13913  return;
13914  }
13915  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13916  {
13917  ErasedFlag = false;
13918  // use 'else' to ensure don't try to access an erased element
13919  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13920  {
13921  ErasePrefDirElementAt(11, x);
13922  ErasedFlag = true;
13923  }
13924  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13925  {
13926  ErasePrefDirElementAt(12, x);
13927  ErasedFlag = true;
13928  }
13929  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13930  {
13931  ErasePrefDirElementAt(13, x);
13932  ErasedFlag = true;
13933  }
13934  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13935  {
13936  ErasePrefDirElementAt(9, x);
13937  ErasedFlag = true;
13938  }
13939  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13940  {
13941  ErasePrefDirElementAt(10, x);
13942  ErasedFlag = true;
13943  }
13944  if(!ErasedFlag)
13945  {
13946  // don't use 'else' here as may be more than one that need decrementing
13947  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13948  {
13949  PrefDirVector.at(x).TrackVectorPosition--;
13950  }
13951  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13952  {
13953  PrefDirVector.at(x).Conn[0]--;
13954  }
13955  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13956  {
13957  PrefDirVector.at(x).Conn[1]--;
13958  }
13959  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13960  {
13961  PrefDirVector.at(x).Conn[2]--;
13962  }
13963  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13964  {
13965  PrefDirVector.at(x).Conn[3]--;
13966  }
13967  }
13968  }
13969  }
13970  Utilities->CallLogPop(1434);
13971 }
13972 
13973 // ---------------------------------------------------------------------------
13974 
13975 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13976 {
13977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13978  OverallDistance = 0;
13979  OverallSpeedLimit = 0;
13980  LeadingPointsAtLastElement = false;
13981  if(PrefDirSize() == 0) // shouldn't be empty when this called
13982  {
13983  Utilities->CallLogPop(1491);
13984  return;
13985  }
13986  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13987  {
13988  LeadingPointsAtLastElement = true;
13989  Utilities->CallLogPop(1492);
13990  return;
13991  }
13992  for(unsigned int x = 0; x < PrefDirSize(); x++)
13993  {
13994  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13995  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13996  {
13997  OverallDistance += PrefDirElement.Length23;
13998  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13999  {
14000  if(x == 0)
14001  {
14002  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14003  }
14004  else
14005  {
14006  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14007  {
14008  OverallSpeedLimit = -1;
14009  }
14010  }
14011  }
14012  }
14013  else
14014  {
14015  OverallDistance += PrefDirElement.Length01;
14016  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14017  {
14018  if(x == 0)
14019  {
14020  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14021  }
14022  else
14023  {
14024  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14025  {
14026  OverallSpeedLimit = -1;
14027  }
14028  }
14029  }
14030  }
14031  }
14032  Utilities->CallLogPop(1529);
14033 }
14034 
14035 // ---------------------------------------------------------------------------
14036 
14037 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14038 {
14039  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14040  if(PrefDirSize() == 0)
14041  {
14042  Utilities->CallLogPop(1564);
14043  return;
14044  }
14045  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14046  bool FoundFlag;
14048  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14049 
14050  while(MMIT != PrefDir4MultiMap.end())
14051  {
14052  HLoc = MMIT->first.first;
14053  VLoc = MMIT->first.second;
14054  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14055  H = HLoc - Track->GetHLocMin();
14056  V = VLoc - Track->GetVLocMin();
14057  // always found in order, any missing have PrefDirPosx == -1
14058  if(PrefDirPos0 > -1)
14059  {
14060  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14061  }
14062  if(PrefDirPos1 > -1)
14063  {
14064  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14065  }
14066  if(PrefDirPos2 > -1)
14067  {
14068  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14069  }
14070  if(PrefDirPos3 > -1)
14071  {
14072  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14073  }
14074  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14075  {
14076  // need to plot all 4 in order to obtain all the direction graphics
14077  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14078  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14079  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14080  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14081  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14082  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14083  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14084  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14085  MMIT++;
14086  MMIT++;
14087  MMIT++;
14088  MMIT++;
14089  }
14090  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14091  {
14092  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14093  {
14094  // 0 & 1 constitute the bidirectional PrefDir
14095  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14096  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14097  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14098  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14099  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14100  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14101  MMIT++;
14102  MMIT++;
14103  MMIT++;
14104  }
14105  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14106  {
14107  // 0 & 2 constitute the bidirectional PrefDir
14108  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14109  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14110  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14111  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14112  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14113  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14114  MMIT++;
14115  MMIT++;
14116  MMIT++;
14117  }
14118  else
14119  {
14120  // 1 & 2 constitute the bidirectional PrefDir
14121  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14122  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14123  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14124  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14125  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14126  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14127  MMIT++;
14128  MMIT++;
14129  MMIT++;
14130  }
14131  }
14132  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14133  {
14134  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14135  {
14136  // 0 & 1 constitute the bidirectional PrefDir
14137  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14138  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14139  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14140  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14141  MMIT++;
14142  MMIT++;
14143  }
14144  else
14145  {
14146  // 2 unidirectional PrefDirs
14147  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14148  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14149  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14150  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14151  MMIT++;
14152  MMIT++;
14153  }
14154  }
14155  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14156  {
14157  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14158  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14159  MMIT++;
14160  }
14161  }
14162  Utilities->CallLogPop(1565);
14163 }
14164 
14165 // ---------------------------------------------------------------------------
14166 
14167 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14168 /*
14169  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14170  level crossing, signals with wrong direction set, or buffers.
14171 */
14172 {
14173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14174  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14175  bool FoundFlag;
14177  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14178 
14179  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14180  ElementIn.VLoc)))
14181  {
14182  Utilities->CallLogPop(1982);
14183  return(false);
14184  }
14185  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14186  {
14187  Utilities->CallLogPop(1983);
14188  return(false);
14189  }
14190 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14191  {
14192  Utilities->CallLogPop(1995);
14193  return(false);
14194  }
14195 */
14196 // Now check that there is only a single prefdir set
14197  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14198 // always found in order, any missing have PrefDirPosx == -1
14199  if(PrefDirPos0 > -1)
14200  {
14201  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14202  }
14203  if(PrefDirPos1 > -1)
14204  {
14205  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14206  }
14207  if(PrefDirPos2 > -1)
14208  {
14209  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14210  }
14211  if(PrefDirPos3 > -1)
14212  {
14213  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14214  }
14215  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14216  {
14217  Utilities->CallLogPop(1984);
14218  return(false);
14219  }
14220  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14221  {
14222  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14223  {
14224  Utilities->CallLogPop(1985);
14225  return(false);
14226  }
14227  else
14228  {
14229  Utilities->CallLogPop(1986);
14230  return(true);
14231  }
14232  }
14233  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14234  {
14235  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14236  {
14237  Utilities->CallLogPop(1987);
14238  return(false);
14239  }
14240  else
14241  {
14242  Utilities->CallLogPop(1988);
14243  return(true);
14244  }
14245  }
14246  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14247  {
14248  if(PrefDirElement0.XLinkPos == EntryPos)
14249  {
14250  Utilities->CallLogPop(1989);
14251  return(false);
14252  }
14253  else
14254  {
14255  Utilities->CallLogPop(1990);
14256  return(true);
14257  }
14258  }
14259  else
14260  {
14261  Utilities->CallLogPop(1991);
14262  return(false); // none found
14263  }
14264 }
14265 
14266 // ---------------------------------------------------------------------------
14267 
14269 {
14270 /* //Added at v2.1.0
14271  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14272  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14273  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14274  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14275  and can be modelled better anyway.
14276 
14277  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14278  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14279  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14280  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14281  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14282  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14283 */
14284  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14285  ElementIn.VLoc + "," + XLink);
14286  int TrackVecPos;
14287  bool TrackFoundFlag;
14288  TTrackElement TempTrackElement;
14289 
14290  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14291  {
14292  Utilities->CallLogPop(2047);
14293  return(false);
14294  }
14295 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14296  if(XLink == 1)
14297  {
14298  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14299  if(TrackFoundFlag)
14300  {
14301  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14302  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14303  {
14304  Utilities->CallLogPop(2048);
14305  return(true);
14306  }
14307  }
14308  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14309  if(TrackFoundFlag)
14310  {
14311  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14312  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14313  {
14314  Utilities->CallLogPop(2049);
14315  return(true);
14316  }
14317  }
14318  }
14319 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14320  if(XLink == 3)
14321  {
14322  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14323  if(TrackFoundFlag)
14324  {
14325  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14326  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14327  {
14328  Utilities->CallLogPop(2050);
14329  return(true);
14330  }
14331  }
14332  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14333  if(TrackFoundFlag)
14334  {
14335  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14336  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14337  {
14338  Utilities->CallLogPop(2051);
14339  return(true);
14340  }
14341  }
14342  }
14343 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14344  if(XLink == 7)
14345  {
14346  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14347  if(TrackFoundFlag)
14348  {
14349  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14350  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14351  {
14352  Utilities->CallLogPop(2052);
14353  return(true);
14354  }
14355  }
14356  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14357  if(TrackFoundFlag)
14358  {
14359  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14360  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14361  {
14362  Utilities->CallLogPop(2053);
14363  return(true);
14364  }
14365  }
14366  }
14367 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14368  if(XLink == 9)
14369  {
14370  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14371  if(TrackFoundFlag)
14372  {
14373  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14374  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14375  {
14376  Utilities->CallLogPop(2054);
14377  return(true);
14378  }
14379  }
14380  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14381  if(TrackFoundFlag)
14382  {
14383  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14384  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14385  {
14386  Utilities->CallLogPop(2055);
14387  return(true);
14388  }
14389  }
14390  }
14391  Utilities->CallLogPop(2056);
14392  return(false);
14393 }
14394 
14395 // ---------------------------------------------------------------------------
14396 
14397 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14398 {
14399 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14400  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14401  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14402  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14403  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14404 */
14405  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14407  bool FoundFlag, ContFlag, FoundElements = false;
14408  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14409  TPrefDirElement NextElement;
14410 
14411  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14412  {
14413  LastIteratorValue++;
14414  ContFlag = false;
14415  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14416  {
14417  continue;
14418  }
14419 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14420  {
14421  continue;
14422  }
14423 */
14424 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14425  // found a potential route start point
14426  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14427  {
14428  continue;
14429  }
14430  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14431  {
14432  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14433  if(PDVIt->TrackType == Continuation)
14434  {
14435  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14436  {
14437  continue;
14438  }
14439  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14440  {
14441  continue;
14442  }
14443  }
14444  StartElement = *PDVIt;
14445 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14446  // diverging track on which there was no pref dir. See below for 2 required changes.
14447  }
14448  else
14449  {
14450  continue;
14451  }
14452  // now track along until find a signal or continuation, checking validity for each element
14453  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14454  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14455  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14456  if(PrefDirPos0 == -1) // no continuing prefdir
14457  {
14458  continue;
14459  }
14460  bool NextElementFoundFlag = false;
14461  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14462  {
14463  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14464  NextElementFoundFlag = true;
14465  }
14466  if(PrefDirPos1 > -1)
14467  {
14468  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14469  {
14470  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14471  NextElementFoundFlag = true;
14472  }
14473  }
14474  if(PrefDirPos2 > -1)
14475  {
14476  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14477  {
14478  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14479  NextElementFoundFlag = true;
14480  }
14481  }
14482  if(PrefDirPos3 > -1)
14483  {
14484  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14485  {
14486  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14487  NextElementFoundFlag = true;
14488  }
14489  }
14490  if(!NextElementFoundFlag)
14491  {
14492  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14493 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14494  }
14495  while(true)
14496  {
14497  // check validity
14498  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14499  {
14500  ContFlag = true;
14501  break;
14502  }
14503  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14504  {
14505  ContFlag = true;
14506  break;
14507  }
14508  // check if in a route, providing not a signal, as a signal might be at the start of a route
14509  if(NextElement.TrackType != SignalPost)
14510  {
14511  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14512  {
14513  ContFlag = true;
14514  break;
14515  }
14516  }
14517  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14518  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
14519  {
14520  EndElement = NextElement;
14521  break;
14522  }
14523  // get the next element in the sequence
14524  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14525  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14526  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14527  if(PrefDirPos0 == -1) // no continuing prefdir
14528  {
14529  ContFlag = true;
14530  break;
14531  }
14532  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14533  {
14534  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14535  continue;
14536  }
14537  if(PrefDirPos1 > -1)
14538  {
14539  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14540  {
14541  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14542  continue;
14543  }
14544  }
14545  if(PrefDirPos2 > -1)
14546  {
14547  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14548  {
14549  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14550  continue;
14551  }
14552  }
14553  if(PrefDirPos3 > -1)
14554  {
14555  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14556  {
14557  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14558  continue;
14559  }
14560  }
14561  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14562  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14563  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14564  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14565  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14566  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14567  {
14568  ContFlag = true;
14569  break;
14570  }
14571  else
14572  {
14573  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14574  // could drop the bridge test but keep it to show the change history
14575  break;
14576 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14577  }
14578  }
14579  if(ContFlag)
14580  {
14581  continue;
14582  }
14583  // else have start and end elements set & all elements valid, so set up the route segment
14584  FoundElements = true;
14585  break;
14586  }
14587  if(FoundElements)
14588  {
14589  Utilities->CallLogPop(1992);
14590  return(true);
14591  }
14592  else
14593  {
14594  Utilities->CallLogPop(1993);
14595  return(false);
14596  }
14597 }
14598 
14599 // ---------------------------------------------------------------------------
14600 // TOneRoute
14601 // ---------------------------------------------------------------------------
14602 
14603 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14604 {
14605 /* General:
14606  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14607  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14608  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14609  route will use automatic signals or not.
14610  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14611  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14612  elements, so additional work is needed to complete all their members before they are ready for conversion into
14613  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14614  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14615  ConvertAndAdd.......
14616 */
14617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14618  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14619  ClearRoute();
14620  int TrackVectorPosition;
14621  TTrackElement TrackElement;
14622  TPrefDirElement FirstElement, LastElement;
14623 
14624  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14625  {
14626  Utilities->CallLogPop(199);
14627  return(false);
14628  }
14629  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14630  {
14631  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14632  Utilities->CallLogPop(1996);
14633  return(false);
14634  }
14635  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14636  {
14637  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14638  Utilities->CallLogPop(200);
14639  return(false);
14640  }
14641  if(Track->IsLCAtHV(18, HLoc, VLoc))
14642  {
14643  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14644  Utilities->CallLogPop(1909);
14645  return(false);
14646  }
14647 // check if selected a train & disallow if so
14648  if(TrackElement.TrainIDOnElement > -1)
14649  {
14650  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14651  Utilities->CallLogPop(202);
14652  return(false);
14653  }
14654 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14655  TPrefDirElement PrefDirElement;
14656  int LockedVectorNumber;
14657 
14658  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14659  {
14660  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14661  Utilities->CallLogPop(203);
14662  return(false);
14663  }
14664  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14665  {
14666  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14667  Utilities->CallLogPop(204);
14668  return(false);
14669  }
14671  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14672 // signal in an autosig route & follow with a non-autosig route
14673 
14674  TPrefDirElement BlankElement;
14675 
14676  StartElement1 = BlankElement;
14677  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14678 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14679  bool InPrefDirFlag = false;
14680 
14681  bool FoundFlag;
14682  int PrefDirPos0 = -1;
14683  int PrefDirPos1 = -1;
14684  int PrefDirPos2 = -1;
14685  int PrefDirPos3 = -1;
14686 
14688  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14689  int PrefDirVecPos[4] =
14690  {
14691  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14692  };
14693 
14694  for(int x = 0; x < 4; x++)
14695  {
14696  int b = PrefDirVecPos[x];
14697  if(b > -1)
14698  {
14699  // only allow the appropriate exit route to be searched
14700  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14701  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14702  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14703  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14704  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14705  {
14706  InPrefDirFlag = true;
14707  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14708  if(AutoSigsFlag)
14709  {
14710  StartElement1.AutoSignals = true;
14711  }
14712  StartElement1.PrefDirRoute = true;
14713  }
14714  }
14715  }
14716 
14717  if(!InPrefDirFlag)
14718  {
14719  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14720  Utilities->CallLogPop(205);
14721  return(false);
14722  }
14723 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14725  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14726 
14727  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14728  {
14729  throw Exception("Selection in two routes - should never happen!");
14730  }
14731  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14732  {
14733  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14734  {
14735  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14736  Utilities->CallLogPop(206);
14737  return(false);
14738  }
14739  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14740  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14741  {
14742  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14743  Utilities->CallLogPop(207);
14744  return(false);
14745  }
14746  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14747  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14748  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14749  {
14750  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14751  Utilities->CallLogPop(208);
14752  return(false);
14753  }
14754  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14756  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14757  if(AutoSigsFlag)
14758  {
14759  StartElement1.AutoSignals = true;
14760  }
14761  StartElement1.PrefDirRoute = true;
14763  Utilities->CallLogPop(209);
14764  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14765  }
14766 
14767  else // no route started
14768  {
14769 // check if selected position is adjacent to start or end of an existing route and disallow
14770  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14771  {
14772  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14773  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14774  {
14775  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14776  Utilities->CallLogPop(210);
14777  return(false);
14778  }
14779  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14780  {
14781  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14782  Utilities->CallLogPop(211);
14783  return(false);
14784  }
14785  }
14786 
14787 // check if it's adjacent to end of an existing route,
14788  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14789  {
14791  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14792  {
14793  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14794  Utilities->CallLogPop(212);
14795  return(false);
14796  }
14797  }
14798  SearchVector.push_back(StartElement1);
14799  Utilities->CallLogPop(213);
14800  return(true);
14801  }
14802 }
14803 
14804 // ---------------------------------------------------------------------------
14805 
14806 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14807  IDInt &ReqPosRouteID, bool &PointsChanged)
14808 
14809 /*
14810  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14811 
14812  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14813  this being set to -1 for not used.
14814  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14815  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14816  Check correct type of element - signal/buffers/continuation.
14817  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14818  EndElement2 corresponding to the 2 possible PrefDir elements).
14819  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14820  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14821  linked forward to another route.
14822  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14823  for same position as start should cover this)
14824 
14825  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14826  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14827  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14828  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14829  If the search fails then return false.
14830  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14831  in the SearchVector to ensure it's entered as part of the new route.
14832  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14833  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14834  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14835  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14836  so return false, with an appropriate message if ConsecSignalsRoute set.
14837 */
14838 
14839 {
14840  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14841  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14842  int EndPosition; // the position selected
14843  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
14844 
14845  Track->LCFoundInAutoSigsRoute = false;
14847  TotalSearchCount = 0;
14848  ReqPosRouteID = IDInt(-1); // default value for not used
14849  TTrackElement TrackElement;
14850  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14851  // given element as can't select 2-track elements
14852  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14853  {
14854  Utilities->CallLogPop(214);
14855  return(false);
14856  }
14857  if(Track->IsLCAtHV(19, HLoc, VLoc))
14858  {
14859  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14860  Utilities->CallLogPop(1908);
14861  return(false);
14862  }
14863 // cancel selection if on original start element
14864  if(EndPosition == StartRoutePosition)
14865  {
14866  Utilities->CallLogPop(215);
14867  return(false);
14868  }
14869  if(AutoSigsFlag)
14870  {
14871  if(TrackElement.TrackType == Buffers)
14872  {
14873  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14874  Utilities->CallLogPop(216);
14875  return(false);
14876  }
14877  }
14878  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14879  {
14880  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14881  Utilities->CallLogPop(217);
14882  return(false);
14883  }
14884 // check if train on element
14885  if(TrackElement.TrainIDOnElement > -1)
14886  {
14887  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14888  Utilities->CallLogPop(219);
14889  return(false);
14890  }
14891 // disallow if not in EveryPrefDir & set EndElement(s)
14892  bool InPrefDirFlag = false;
14893 
14894  bool FoundFlag;
14895  int PrefDirPos0 = -1;
14896  int PrefDirPos1 = -1;
14897  int PrefDirPos2 = -1;
14898  int PrefDirPos3 = -1;
14899 
14900  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14901  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14902  int PrefDirVecPos[4] =
14903  {
14904  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14905  };
14906 
14907  for(int x = 0; x < 4; x++)
14908  {
14909  int b = PrefDirVecPos[x];
14910  if(b > -1)
14911  {
14912  InPrefDirFlag = true;
14913  if(EndElement1.TrackVectorPosition == -1)
14914  {
14915  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14916  }
14917  else
14918  {
14919  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14920  }
14921  }
14922  }
14923  if(!InPrefDirFlag)
14924  {
14925  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14926  Utilities->CallLogPop(220);
14927  return(false);
14928  }
14929 // check if in an existing route - can't be a bridge so can use a simple 'find'
14930 // bool InRoute = false;
14932  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14933 
14934  if(RoutePair.first > -1)
14935  {
14936  if(RoutePair.second != 0) // not first element in existing route so no good
14937  {
14938  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14939  Utilities->CallLogPop(221);
14940  return(false);
14941  }
14942  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14943 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14944  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14945  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14946  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14947  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14948  {
14949  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14950  Utilities->CallLogPop(222);
14951  return(false);
14952  }
14953  EndElement1 = RouteElement;
14954  EndElement2 = BlankElement; // only need the route element
14955  EndPosition = EndElement1.TrackVectorPosition;
14956  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14957  }
14958 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14959 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14960 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14961 
14962  if(EndElement1.HLoc >= StartElement1.HLoc)
14963  {
14965  SearchLimitHighH = EndElement1.HLoc + 15;
14966  }
14967  else
14968  {
14969  SearchLimitLowH = EndElement1.HLoc - 15;
14971  }
14972  if(EndElement1.VLoc >= StartElement1.VLoc)
14973  {
14975  SearchLimitHighV = EndElement1.VLoc + 15;
14976  }
14977  else
14978  {
14979  SearchLimitLowV = EndElement1.VLoc - 15;
14981  }
14982 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14983  check & TotalSearchCounts check
14984  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14985  {
14986  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14987  Utilities->CallLogPop(1693);
14988  return false;
14989  }
14990 */
14991 // check if adjacent to start and disallow
14992  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14993  {
14995  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14996 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14997 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14998  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14999  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15000  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15001  {
15002  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15003  Utilities->CallLogPop(223);
15004  return(false);
15005  }
15006 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15007 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15008  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15009  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15010  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15011  {
15012  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15013  Utilities->CallLogPop(224);
15014  return(false);
15015  }
15016 // check if adjacent to end of a route & disallow
15018  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15019  {
15020  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15021  Utilities->CallLogPop(225);
15022  return(false);
15023  }
15024  }
15025 
15026 // check for same route as start element
15028  {
15029  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15030  Utilities->CallLogPop(226);
15031  return(false);
15032  }
15033 // check for a looping route
15034  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15035  {
15037  {
15038  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15039  Utilities->CallLogPop(1844);
15040  return(false);
15041  }
15042  }
15043 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15044 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15045 // and don't want to add it again
15046  if(StartSelectionRouteID > -1)
15047  {
15048  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15049  AutoSigsFlag, false))
15050  {
15051  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15052  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15053  {
15054  if(NewFailedPointsTVPos > -1)
15055  {
15056  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15057  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15058  " failed during route setting.");
15059  Utilities->CallLogPop(2488);
15060  return(false);
15061  }
15062  PointsChanged = true;
15063  }
15064  Utilities->CallLogPop(227);
15065  return(true);
15066  }
15067  else if(!Track->SuppressRouteFailMessage)
15068  {
15069  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15071  Utilities->CallLogPop(228);
15072  return(false);
15073  }
15074  }
15075  else
15076  {
15077 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15078 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15079 
15080 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15081 // note that a blank element will have XLinkPos set to -1
15082  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15083  {
15084  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15085  AutoSigsFlag, false))
15086  {
15087  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15088  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15089  {
15090  if(NewFailedPointsTVPos > -1)
15091  {
15092  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15093  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15094  " failed during route setting.");
15095  Utilities->CallLogPop(2490);
15096  return(false);
15097  }
15098  PointsChanged = true;
15099  }
15100  Utilities->CallLogPop(229);
15101  return(true);
15102  }
15103  else
15104  {
15106  {
15108  }
15109  Utilities->CallLogPop(230);
15110  return(false);
15111  }
15112  }
15113  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15114  {
15115  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15116  AutoSigsFlag, false))
15117  {
15118  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15119  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15120  {
15121  if(NewFailedPointsTVPos > -1)
15122  {
15123  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15124  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15125  " failed during route setting.");
15126  Utilities->CallLogPop(2492);
15127  return(false);
15128  }
15129  PointsChanged = true;
15130  }
15131  Utilities->CallLogPop(231);
15132  return(true);
15133  }
15134  else
15135  {
15137  {
15139  }
15140  Utilities->CallLogPop(232);
15141  return(false);
15142  }
15143  }
15144  // now start off in the best direction
15145  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15146  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15147  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15148  // unless new problems are found.
15149  if(StartElement1.XLinkPos == BestPos)
15150  {
15151  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15152  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15153  AutoSigsFlag, false))
15154  {
15155  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15156  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15157  {
15158  if(NewFailedPointsTVPos > -1)
15159  {
15160  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15161  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15162  " failed during route setting.");
15163  Utilities->CallLogPop(2494);
15164  return(false);
15165  }
15166  PointsChanged = true;
15167  }
15168  Utilities->CallLogPop(233);
15169  return(true);
15170  }
15171  else if(StartElement2.TrackVectorPosition > -1)
15172  {
15173  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15174  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15175  AutoSigsFlag, false))
15176  {
15177  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15178  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15179  {
15180  if(NewFailedPointsTVPos > -1)
15181  {
15182  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15183  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15184  " failed during route setting.");
15185  Utilities->CallLogPop(2496);
15186  return(false);
15187  }
15188  PointsChanged = true;
15189  }
15190  Utilities->CallLogPop(234);
15191  return(true);
15192  }
15193  }
15194  }
15195  else if(StartElement2.TrackVectorPosition > -1)
15196  {
15197  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15198  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15199  AutoSigsFlag, false))
15200  {
15201  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15202  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15203  {
15204  if(NewFailedPointsTVPos > -1)
15205  {
15206  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15207  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15208  " failed during route setting.");
15209  Utilities->CallLogPop(2498);
15210  return(false);
15211  }
15212  PointsChanged = true;
15213  }
15214  Utilities->CallLogPop(1857);
15215  return(true);
15216  }
15217  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15218  AutoSigsFlag, false))
15219  {
15220  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15221  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15222  {
15223  if(NewFailedPointsTVPos > -1)
15224  {
15225  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15226  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15227  " failed during route setting.");
15228  Utilities->CallLogPop(2500);
15229  return(false);
15230  }
15231  PointsChanged = true;
15232  }
15233  Utilities->CallLogPop(1858);
15234  return(true);
15235  }
15236  }
15237  else if(StartElement1.XLinkPos == (1 - BestPos))
15238  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15239  {
15240  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15241  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15242  AutoSigsFlag, false))
15243  {
15244  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15245  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15246  {
15247  if(NewFailedPointsTVPos > -1)
15248  {
15249  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15250  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15251  " failed during route setting.");
15252  Utilities->CallLogPop(2502);
15253  return(false);
15254  }
15255  PointsChanged = true;
15256  }
15257  Utilities->CallLogPop(1864);
15258  return(true);
15259  }
15260  }
15261  }
15263  {
15265  }
15266  Utilities->CallLogPop(235);
15267  return(false);
15268 }
15269 
15270 // ---------------------------------------------------------------------------
15271 
15272 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15273 {
15274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15275  if(PrefDirSize() == 0)
15276  {
15277  Utilities->CallLogPop(1704);
15278  return;
15279  }
15280  for(unsigned int x = 0; x < PrefDirSize(); x++)
15281  {
15282  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15283  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15284  {
15285  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15286  TempPrefDirElement.EXGraphicPtr);
15287  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15288  {
15289  if(x == 0)
15290  {
15291  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15292  TempPrefDirElement.EntryDirectionGraphicPtr);
15293  }
15294  if(x == (PrefDirSize() - 1))
15295  {
15296  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15297  TempPrefDirElement.EntryDirectionGraphicPtr);
15298  }
15299  }
15300  }
15301  }
15302 
15303  Utilities->CallLogPop(1705);
15304 }
15305 
15306 // ---------------------------------------------------------------------------
15307 
15308 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15309  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15310 /*
15311  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15312  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15313  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15314  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15315  Return false if any element (apart from RequiredPosition) is on an existing route.
15316  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15317 
15318  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15319  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15320  added during the function so as to leave it exactly as it was on entering, then return false).
15321  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15322  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15323  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15324  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15325  the route number that the searched-for element is the start of if any, and set to -1 if no
15326  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15327  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15328  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15329  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15330 
15331  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15332  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15333  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15334  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15335  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15336  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15337  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15338  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15339  or if train on element (unless a bridge & train on different track).
15340  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15341  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15342  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15343  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15344  AutoSignals member set if AutoSigsFlag set, then return true.
15345  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15346 
15347  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15348  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15349  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15350  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15351  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15352  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15353  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15354 
15355  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15356  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15357 */
15358 
15359 {
15360  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15361  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15362  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
15363  int VectorCount = 0;
15364  if(!RecursiveCall) //added at v2.15.1
15365  {
15367  }
15368 
15369  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15370 
15371 // check for a fouled diagonal for first element. Added for v1.3.2
15372  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15373  {
15374  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15375  {
15376  for(int x = 0; x < VectorCount; x++)
15377  {
15378  SearchVector.erase(SearchVector.end() - 1);
15379  }
15380  Utilities->CallLogPop(2043);
15381  return(false);
15382  }
15383  }
15384  bool FirstPass = true;
15385 
15386  while(true)
15387  {
15388  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15389  {
15390  Track->LCFoundInAutoSigsRoute = true;
15391  }
15392  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15393  {
15394  for(int x = 0; x < VectorCount; x++)
15395  {
15396  SearchVector.erase(SearchVector.end() - 1);
15397  }
15398  Utilities->CallLogPop(1926);
15399  return(false);
15400  }
15401  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15402  {
15403  for(int x = 0; x < VectorCount; x++)
15404  {
15405  SearchVector.erase(SearchVector.end() - 1);
15406  }
15407  Utilities->CallLogPop(236);
15408  return(false);
15409  }
15410  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15411  // reached a valid signal that isn't the required position, user should always select the next
15412  // signal in a route when ConsecSignals is true so have to fail
15413  // won't affect recurive searches as for them the first pass element is always a point
15414  {
15415  for(int x = 0; x < VectorCount; x++)
15416  {
15417  SearchVector.erase(SearchVector.end() - 1);
15418  }
15419  Utilities->CallLogPop(237);
15420  return(false);
15421  }
15422  FirstPass = false;
15423  int NextPosition = PrefDirElement.Conn[XLinkPos];
15424  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15425  TPrefDirElement SearchElement(NextTrackElement);
15426  SearchElement.TrackVectorPosition = NextPosition;
15427  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15428  SearchElement.ELinkPos = NextELinkPos;
15429  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15430  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15431  int NextXLinkPos;
15432  if(SearchElement.ELinkPos == 0)
15433  {
15434  NextXLinkPos = 1;
15435  }
15436  if(SearchElement.ELinkPos == 1)
15437  {
15438  NextXLinkPos = 0;
15439  }
15440  if(SearchElement.ELinkPos == 2)
15441  {
15442  NextXLinkPos = 3;
15443  }
15444  if(SearchElement.ELinkPos == 3)
15445  {
15446  NextXLinkPos = 2;
15447  }
15448  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15449  {
15450  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15451 // note that may be buffers, continuation or gap
15452  SearchElement.XLinkPos = NextXLinkPos;
15453  }
15454 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15455 
15456 // drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop
15457 /*
15458 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15459  for(unsigned int x = 0; x < SearchVector.size(); x++)
15460  {
15461  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15462  {
15463  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15464  // OK if a bridge & routes on different tracks
15465  {
15466  for(int x = 0; x < VectorCount; x++)
15467  {
15468  SearchVector.erase(SearchVector.end() - 1);
15469  }
15470  Utilities->CallLogPop(238);
15471  return(false);
15472  }
15473  }
15474  }
15475 */
15476 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15477  TAllRoutes::TRouteElementPair SecondPair;
15479  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15480  if(RoutePair.first > -1)
15481  {
15482  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15483  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15484  RoutePair.second).ELinkPos)))
15485  {
15486  // still OK if start of an expected route
15487  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15488  {
15489  for(int x = 0; x < VectorCount; x++)
15490  {
15491  SearchVector.erase(SearchVector.end() - 1);
15492  }
15493  Utilities->CallLogPop(239);
15494  return(false); // only allow for start of an expected route
15495  }
15496  }
15497  }
15498  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15499  {
15500  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15501  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15502  SecondPair.second).ELinkPos)))
15503  {
15504  // still OK if start of an expected route
15505  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15506  {
15507  for(int x = 0; x < VectorCount; x++)
15508  {
15509  SearchVector.erase(SearchVector.end() - 1);
15510  }
15511  Utilities->CallLogPop(240);
15512  return(false); // only allow for start of an expected route
15513  }
15514  }
15515  }
15516 // check if a train on element, unless a bridge & train on different track
15517 // OK of same train as start element - no drop this
15518 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15519  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15520  {
15521  for(int x = 0; x < VectorCount; x++)
15522  {
15523  SearchVector.erase(SearchVector.end() - 1);
15524  }
15525  Utilities->CallLogPop(241);
15526  return(false);
15527  }
15528  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15529  {
15530  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
15531  {
15532  for(int x = 0; x < VectorCount; x++)
15533  {
15534  SearchVector.erase(SearchVector.end() - 1);
15535  }
15536  Utilities->CallLogPop(242);
15537  return(false);
15538  }
15539  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
15540  {
15541  for(int x = 0; x < VectorCount; x++)
15542  {
15543  SearchVector.erase(SearchVector.end() - 1);
15544  }
15545  Utilities->CallLogPop(243);
15546  return(false);
15547  }
15548  }
15549 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15550  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15551  {
15552  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15553  {
15554  for(int x = 0; x < VectorCount; x++)
15555  {
15556  SearchVector.erase(SearchVector.end() - 1);
15557  }
15558  Utilities->CallLogPop(244);
15559  return(false);
15560  }
15561  }
15562 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15563 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15564  bool InPrefDirFlag = false;
15565  PrefDirElement1 = BlankElement;
15566  PrefDirElement2 = BlankElement;
15567 
15568  bool FoundFlag;
15569  int PrefDirPos0 = -1;
15570  int PrefDirPos1 = -1;
15571  int PrefDirPos2 = -1;
15572  int PrefDirPos3 = -1;
15574  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15575  int PrefDirVecPos[4] =
15576  {
15577  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15578  };
15579  for(int x = 0; x < 4; x++)
15580  {
15581  int b = PrefDirVecPos[x];
15582  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15583  {
15584  InPrefDirFlag = true;
15585  if(PrefDirElement1.TrackVectorPosition == -1)
15586  {
15587  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15588  }
15589  else
15590  {
15591  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15592  }
15593  }
15594  }
15595  if(!InPrefDirFlag)
15596  {
15597  for(int x = 0; x < VectorCount; x++)
15598  {
15599  SearchVector.erase(SearchVector.end() - 1);
15600  }
15601  Utilities->CallLogPop(245);
15602  return(false);
15603  }
15604 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15605 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15606 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15608  {
15609  for(int x = 0; x < VectorCount; x++)
15610  {
15611  SearchVector.erase(SearchVector.end() - 1);
15612  }
15613  Utilities->CallLogPop(1690);
15614  return(false);
15615  }
15616 // check if found it
15617  if(SearchElement.TrackVectorPosition == RequiredPosition)
15618  {
15619 // need to ensure a signal/buffer/continuation
15620 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
15621  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
15622  {
15623  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15625  for(int x = 0; x < VectorCount; x++)
15626  {
15627  SearchVector.erase(SearchVector.end() - 1);
15628  }
15629  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
15630  Utilities->CallLogPop(246);
15631  return(false);
15632  } // if((SearchElement.TrackType != SignalPost) &&.......
15633 //need to make sure it's in the right direction
15634  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
15635  { //condition added at v2.16.1
15636  for(int x = 0; x < VectorCount; x++)
15637  {
15638  SearchVector.erase(SearchVector.end() - 1);
15639  }
15640  Utilities->CallLogPop(2627);
15641  return(false);
15642  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
15643 
15644  if(AutoSigsFlag)
15645  {
15646  PrefDirElement1.AutoSignals = true;
15647  }
15648  PrefDirElement1.PrefDirRoute = true;
15650  {
15652  {
15653  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15655  }
15656  for(int x = 0; x < VectorCount; x++)
15657  {
15658  SearchVector.erase(SearchVector.end() - 1);
15659  }
15660  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
15661  Utilities->CallLogPop(1928);
15662  return(false);
15663  }
15664  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15665  VectorCount++; // not really needed but include for tidyness
15666  TotalSearchCount++;
15667  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
15668  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
15669  for(int x = 0; x < VectorCount; x++)
15670  {
15671  SearchVector.erase(SearchVector.end() - 1);
15672  }
15673  Utilities->CallLogPop(2522);
15674  return(false);
15675  }
15676  Utilities->CallLogPop(247);
15677  return(true);
15678  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15679 
15680 // check if a buffer or continuation (end of search on this leg if not found by now)
15681  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15682  {
15683  for(int x = 0; x < VectorCount; x++)
15684  {
15685  SearchVector.erase(SearchVector.end() - 1);
15686  }
15687  Utilities->CallLogPop(248);
15688  return(false);
15689  }
15690 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
15692  {
15693  for(int x = 0; x < VectorCount; x++)
15694  {
15695  SearchVector.erase(SearchVector.end() - 1);
15696  }
15697  Utilities->CallLogPop(1420);
15698  return(false);
15699  }
15700 //deal with failed points, added at v2.13.0
15701  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
15702  {
15703  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
15704  {
15705  SearchElement.XLinkPos = 1;
15706  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15707  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15708  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15709  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15710  }
15711  else
15712  {
15713  SearchElement.XLinkPos = 3;
15714  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15715  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15716  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15717  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15718  }
15719  }
15720  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
15721  {
15722  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
15723  {
15724  for(int x = 0; x < VectorCount; x++)
15725  {
15726  SearchVector.erase(SearchVector.end() - 1);
15727  }
15728  Utilities->CallLogPop(2514);
15729  return(false);
15730  }
15731  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
15732  {
15733  for(int x = 0; x < VectorCount; x++)
15734  {
15735  SearchVector.erase(SearchVector.end() - 1);
15736  }
15737  Utilities->CallLogPop(2515);
15738  return(false);
15739  }
15740  }
15741 // check if reached a non-failed leading point
15742  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
15743  {
15744 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15745  int SearchPos1 = SearchElement.Attribute + 1;
15746  int SearchPos2;
15747  if(SearchPos1 == 2)
15748  {
15749  SearchPos1++;
15750  }
15751  if(SearchPos1 == 1)
15752  {
15753  SearchPos2 = 3;
15754  }
15755  else
15756  {
15757  SearchPos2 = 1;
15758  }
15759  SearchElement.XLink = SearchElement.Link[SearchPos1];
15760  SearchElement.XLinkPos = SearchPos1;
15761  InPrefDirFlag = false;
15762  if(SearchElement.XLink == PrefDirElement1.XLink)
15763  {
15764  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15765  InPrefDirFlag = true;
15766  }
15767  else if(SearchElement.XLink == PrefDirElement2.XLink)
15768  {
15769  SearchElement = PrefDirElement2;
15770  InPrefDirFlag = true;
15771  }
15772 // push element with XLink set to position [SearchPos1] if on a PrefDir
15773  if(InPrefDirFlag)
15774  {
15775 // check for a fouled diagonal for leading point for XLinkPos == 1)
15776  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15777  {
15778  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15779  {
15780  for(int x = 0; x < VectorCount; x++)
15781  {
15782  SearchVector.erase(SearchVector.end() - 1);
15783  }
15784  Utilities->CallLogPop(249);
15785  return(false);
15786  }
15787  }
15788  if(AutoSigsFlag)
15789  {
15790  SearchElement.AutoSignals = true;
15791  }
15792  SearchElement.PrefDirRoute = true;
15793  SearchVector.push_back(SearchElement);
15794  VectorCount++;
15795  TotalSearchCount++;
15796 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15797  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15798  AutoSigsFlag, true))
15799  {
15801  {
15803  {
15804  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15806  }
15807  for(int x = 0; x < VectorCount; x++)
15808  {
15809  SearchVector.erase(SearchVector.end() - 1);
15810  }
15811  Utilities->CallLogPop(1929);
15812  return(false);
15813  }
15814  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
15815  {
15816  for(int x = 0; x < VectorCount; x++)
15817  {
15818  SearchVector.erase(SearchVector.end() - 1);
15819  }
15820  Utilities->CallLogPop(2523);
15821  return(false);
15822  }
15823  Utilities->CallLogPop(250);
15824  return(true);
15825  }
15826  else
15827  {
15828 // remove leading point with XLinkPos [1]
15829  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
15830  {
15831  SearchVector.erase(SearchVector.end() - 1);
15832  VectorCount--;
15833  }
15834  else
15835  {
15836  for(int x = 0; x < VectorCount; x++)
15837  {
15838  SearchVector.erase(SearchVector.end() - 1);
15839  }
15840  Utilities->CallLogPop(2626);
15841  return(false);
15842  }
15843  }
15844  }
15845 // XLink set to position [SearchPos2]
15846  SearchElement.XLink = SearchElement.Link[SearchPos2];
15847  SearchElement.XLinkPos = SearchPos2;
15848  if(SearchElement.XLink == PrefDirElement1.XLink)
15849  {
15850  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15851  }
15852  else if(SearchElement.XLink == PrefDirElement2.XLink)
15853  {
15854  SearchElement = PrefDirElement2;
15855  }
15856  else // failed to find a valid exit from the point
15857  {
15858  for(int x = 0; x < VectorCount; x++)
15859  {
15860  SearchVector.erase(SearchVector.end() - 1);
15861  }
15862  Utilities->CallLogPop(251);
15863  return(false);
15864  }
15865 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15866  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15867  {
15868  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15869  {
15870  for(int x = 0; x < VectorCount; x++)
15871  {
15872  SearchVector.erase(SearchVector.end() - 1);
15873  }
15874  Utilities->CallLogPop(252);
15875  return(false);
15876  }
15877  }
15878 // push element with XLink set to position [SearchPos2]
15879  if(AutoSigsFlag)
15880  {
15881  SearchElement.AutoSignals = true;
15882  }
15883  SearchElement.PrefDirRoute = true;
15884  SearchVector.push_back(SearchElement);
15885  VectorCount++;
15886  TotalSearchCount++;
15887 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15888  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15889  AutoSigsFlag, true))
15890  {
15892  {
15894  {
15895  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15897  }
15898  for(int x = 0; x < VectorCount; x++)
15899  {
15900  SearchVector.erase(SearchVector.end() - 1);
15901  }
15902  Utilities->CallLogPop(1930);
15903  return(false);
15904  }
15905  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
15906  {
15907  for(int x = 0; x < VectorCount; x++)
15908  {
15909  SearchVector.erase(SearchVector.end() - 1);
15910  }
15911  Utilities->CallLogPop(2524);
15912  return(false);
15913  }
15914  Utilities->CallLogPop(1592);
15915  return(true);
15916  }
15917  else
15918  {
15919  for(int x = 0; x < VectorCount; x++)
15920  {
15921  SearchVector.erase(SearchVector.end() - 1);
15922  }
15923  Utilities->CallLogPop(253);
15924  return(false);
15925  }
15926  } // if leading point
15927 
15928 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15929  SearchElement = PrefDirElement1;
15930  if(AutoSigsFlag)
15931  {
15932  SearchElement.AutoSignals = true;
15933  }
15934  SearchElement.PrefDirRoute = true;
15935  SearchVector.push_back(SearchElement);
15936  VectorCount++;
15937  TotalSearchCount++;
15938  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15939  PrefDirElement = SearchElement;
15940  } // while(true)
15941 }
15942 
15943 // ---------------------------------------------------------------------------
15944 
15945 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15946 {
15947 /*
15948  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15949  and the new or extended route created from that. Hence action varies depending on whether
15950  it is a completely new route, or an extension of an existing route at the beginning or the end.
15951  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15952  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15953 
15954  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15955  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15956  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15957  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15958  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15959  is decremented;
15960  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15961  from the existing route, then enter the new route into the AllRoutesVector;
15962  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15963  then enter the new route into the AllRoutesVector.
15964 
15965  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15966  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15967  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15968  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15969  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15970  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15971  for the new route and return;
15972  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15973  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15974 
15975  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15976  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15977  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15978 
15979 */
15980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15981  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15982  if(SearchVector.size() < 1)
15983  {
15984  Utilities->CallLogPop(254);
15985  return;
15986  }
15988  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15989  {
15990  Utilities->CallLogPop(255);
15991  return;
15992  }
15993  TAllRoutes::TLockedRouteClass LockedRouteObject;
15994 
15996  unsigned int TruncatePrefDirPosition = 0;
15997 
15998  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15999 /* if have ReqPosRouteID:
16000  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16001  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16002  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16003  the existing route, then enter the new route into the AllRoutesVector
16004  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16005  then enter the new route into the AllRoutesVector
16006 */
16007  {
16010  {
16011  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16012  x++) // start at 1 as first element already in SearchVector
16013  {
16015  }
16016  // note that route numbers in map adjusted when ReqPos route cleared
16018  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16019  // set during ClearRouteDuringRouteBuildingAt
16021  {
16024  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16025  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16026  }
16027  }
16029  {
16031  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16032  }
16034  {
16035  SearchVector.pop_back();
16036  }
16037  }
16038  if(StartSelectionRouteID > -1)
16039 /* if have StartSelectionRouteID:
16040  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16041  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16042  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16043  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16044  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16045 */
16046  {
16048  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16049  {
16052  {
16053  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16054  for(unsigned int x = 0; x < SearchVector.size(); x++)
16055  {
16057  RouteNumber, GetFixedSearchElementAt(3, x));
16058  // find & store locked route truncate position in PrefDirVector for later use
16060  {
16061  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16062  {
16063  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16064  }
16065  }
16066  }
16068  {
16069  throw Exception("Error - failed to validate extended route for preferred route");
16070  }
16073  if(!AutoSigsFlag)
16074  {
16075  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16076  }
16077  // now add the reinstated locked route if required and set signals accordingly
16079  {
16080  LockedRouteObject.RouteNumber = RouteNumber;
16081  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16082  // now reset the signals for the locked route
16083  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16084  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16085  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16086  {
16087  // return all signals to red in route section to be truncated
16088  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16089  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16090  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16091  {
16092  TrackElement.Attribute = 0;
16093  Track->PlotSignal(10, TrackElement, Display);
16094  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16095  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16096  }
16097  }
16098  }
16099  AllRoutes->CheckMapAndRoutes(1); // test
16100  Utilities->CallLogPop(256);
16101  return;
16102  }
16104  {
16107  RouteElement.AutoSignals = true;
16108  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16109  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16110  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16111  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16112  }
16113  }
16114  else
16115  {
16117  }
16118 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16119 // AllRoutesVector hence nothing to do here
16120  }
16121  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16122  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16123  {
16124  throw Exception("Error - failed to validate single route for preferred route");
16125  }
16126  AllRoutes->StoreOneRoute(1, this);
16127  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16128  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16129  if(!AutoSigsFlag)
16130  {
16131  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16132  }
16133  AllRoutes->CheckMapAndRoutes(2); // test
16134  Utilities->CallLogPop(257);
16135 }
16136 
16137 // ---------------------------------------------------------------------------
16138 
16139 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16140 {
16141 /*
16142  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16143  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16144  & ensure signal/buffers/continuation.
16145  Note that can't select ConsecSignalsRoute for non-preferred routes.
16146  Check if train on element & disallow.
16147  Set default values for retained parameters:-
16148  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16149  StartSelectionRouteID = route that selection starts in if there is one;
16150 
16151  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16152  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16153  validity. This is just for safety reasons, the PrefDir values aren't used.
16154  StartElement1 & 2 are set to these PrefDirelements.
16155 
16156  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16157 
16158  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16159  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16160  blank StartElement2 (only want to use the route element), then return true.
16161  Check if adjacent to start or end of an existing route & disallow if so.
16162  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16163  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16164  SetRemainingSearchVectorValues().
16165  Finally add the required element to the SearchVector & return true.
16166 
16167 */
16168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16169  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16170  ClearRoute();
16171  int TrackVectorPosition;
16172  TTrackElement TrackElement;
16173  TPrefDirElement FirstElement, LastElement;
16174 
16175  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16176  {
16177  Utilities->CallLogPop(258);
16178  return(false);
16179  }
16180  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16181  {
16182  if(!Callon)
16183  {
16184  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16185  }
16186 // makes later adjacent route checks too complicated
16187  Utilities->CallLogPop(259);
16188  return(false);
16189  }
16190  if(Track->IsLCAtHV(21, HLoc, VLoc))
16191  {
16192  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16193  Utilities->CallLogPop(1910);
16194  return(false);
16195  }
16196 // check if selected a train & disallow if so
16197  if(TrackElement.TrainIDOnElement > -1)
16198  {
16199  if(!Callon)
16200  {
16201  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16202  }
16203  Utilities->CallLogPop(260);
16204  return(false);
16205  }
16206 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16207  TPrefDirElement PrefDirElement;
16208  int LockedVectorNumber;
16209 
16210  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16211  {
16212  if(!Callon)
16213  {
16214  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16215  }
16216  Utilities->CallLogPop(261);
16217  return(false);
16218  }
16219  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16220  {
16221  if(!Callon)
16222  {
16223  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16224  }
16225  Utilities->CallLogPop(262);
16226  return(false);
16227  }
16229 // AdjacentStartRouteNumber = -1;
16230  StartRoutePosition = TrackVectorPosition;
16231 // StartRouteSelectPosition = TrackVectorPosition;
16232 
16233  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16234  TPrefDirElement PrefDirElement2(TrackElement);
16235 
16236  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16237  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16238  TPrefDirElement BlankElement;
16239 
16240  PrefDirElement1.ELinkPos = 0;
16241  PrefDirElement1.XLinkPos = 1;
16242  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16243  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16244  if(!(PrefDirElement1.EntryExitNumber()))
16245  {
16246  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16247  // no need for bridge check as bridge selections not allowed
16248  }
16249  PrefDirElement1.CheckCount = 9;
16250  PrefDirElement2.ELinkPos = 1;
16251  PrefDirElement2.XLinkPos = 0;
16252  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16253  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16254  if(!(PrefDirElement2.EntryExitNumber()))
16255  {
16256  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16257  }
16258  PrefDirElement2.CheckCount = 9; // both now set
16259 
16260 // set StartElements to the above PrefDirElements
16261  StartElement1 = PrefDirElement1;
16262  StartElement2 = PrefDirElement2;
16263 
16264 // no PrefDir check needed as doesn't need to be in a PrefDir
16265 
16266 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16268  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16269 
16270  if(RoutePair.first > -1)
16271  {
16272  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16273  {
16274  if(!Callon)
16275  {
16276  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16277  }
16278  Utilities->CallLogPop(263);
16279  return(false);
16280  }
16281  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16282  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16283  {
16284  if(!Callon)
16285  {
16286  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16287  }
16288  Utilities->CallLogPop(264);
16289  return(false);
16290  }
16291  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16292  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16293  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16294  {
16295  if(!Callon)
16296  {
16297  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16298  }
16299  Utilities->CallLogPop(265);
16300  return(false);
16301  }
16302  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16304  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16305  StartElement2 = BlankElement; // only use the route element
16307  Utilities->CallLogPop(266);
16308  return(true); // all retained values set
16309  }
16310 
16311  else // selection not in an existing route
16312  {
16313 // check if it's adjacent to start of an an existing route,
16314  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16315  {
16316  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16317  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16318  {
16319  if(!Callon)
16320  {
16321  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16322  }
16323  Utilities->CallLogPop(267);
16324  return(false);
16325  }
16326  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16327  {
16328  if(!Callon)
16329  {
16330  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16331  }
16332  Utilities->CallLogPop(268);
16333  return(false);
16334  }
16335  }
16336 // check if it's adjacent to end of an an existing route,
16337  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16338  {
16340  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16341  {
16342  if(!Callon)
16343  {
16344  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16345  }
16346  Utilities->CallLogPop(269);
16347  return(false);
16348  }
16349  }
16350  // not in a route or adjacent to start or end of a route
16351  // in this case reset all variable values to -1 & CheckCount to 4
16352  StartElement1.ELink = -1;
16353  StartElement1.ELinkPos = -1;
16354  StartElement1.XLink = -1;
16355  StartElement1.XLinkPos = -1;
16356  StartElement1.EXNumber = -1;
16357  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16358  StartElement2 = BlankElement;
16359  SearchVector.push_back(StartElement1);
16360  Utilities->CallLogPop(270);
16361  return(true);
16362  }
16363 }
16364 
16365 // ---------------------------------------------------------------------------
16366 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16367 
16368 /*
16369  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16370 
16371  Declare the following integers:-
16372  EndPosition - TrackVectorPosition for the selection;
16373  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16374  Check if selection is a valid track element and set EndPosition.
16375  Cancel if select original start element, then check that not points, bridge or crossover.
16376  Check & fail if a train is present at the selection.
16377  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16378  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16379  No check needed for selection in EveryPrefDir.
16380  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16381  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16382  as don't need it if in a route.
16383  Check if selection adj to start or end of a route and disallow.
16384  Fail if select same route as starting route, though should already have failed earlier if this is so.
16385 
16386  If there's a StartSelectionRouteID then StartElement1 will be set to
16387  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16388  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16389  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16390  to add the new route to the AllRoutesVectorPtr.
16391  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16392  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16393  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16394  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16395  the search vector values and return.
16396  If not returned yet then have failed to find the required element so return false with no message.
16397 
16398 */
16399 
16400 {
16401 // get EndPosition
16402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16403  AnsiString(VLoc));
16404  int EndPosition;
16405  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16406 
16407  TotalSearchCount = 0;
16408  ReqPosRouteID = IDInt(-1); // for not used
16409  TTrackElement TrackElement;
16410  TPrefDirElement BlankElement;
16412 
16413  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16414  {
16415  Utilities->CallLogPop(271);
16416  return(false);
16417  }
16418 // EndPosition = EndSelectPosition;
16419 // cancel selection if on original start element
16420  if(EndPosition == StartRoutePosition)
16421  {
16422  Utilities->CallLogPop(272);
16423  return(false);
16424  }
16425  if(Track->IsLCAtHV(22, HLoc, VLoc))
16426  {
16427  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16428  Utilities->CallLogPop(1911);
16429  return(false);
16430  }
16431  if((TrackElement.TrackType == Points) && !Callon)
16432  {
16433  if(!Callon)
16434  {
16435  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16436  }
16437 // makes later adjacent route checks too complicated
16438  Utilities->CallLogPop(273);
16439  return(false);
16440  }
16441  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16442  {
16443  if(!Callon)
16444  {
16445  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16446  }
16447 // makes later adjacent route checks too complicated
16448  Utilities->CallLogPop(1861);
16449  return(false);
16450  }
16451 // check if train on element
16452  if(TrackElement.TrainIDOnElement > -1)
16453  {
16454  if(!Callon)
16455  {
16456  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
16457  }
16458  Utilities->CallLogPop(274);
16459  return(false);
16460  }
16461 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
16462 // check passed)
16463  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16464  TPrefDirElement EndElement2(TrackElement);
16465 
16466  EndElement1.TrackVectorPosition = EndPosition;
16467  EndElement2.TrackVectorPosition = EndPosition;
16468  EndElement1.ELinkPos = 0;
16469  EndElement1.XLinkPos = 1;
16470  EndElement1.ELink = EndElement1.Link[0];
16471  EndElement1.XLink = EndElement1.Link[1];
16472  if(!(EndElement1.EntryExitNumber()))
16473  {
16474  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
16475  }
16476  EndElement1.CheckCount = 9;
16477  EndElement2.ELinkPos = 1;
16478  EndElement2.XLinkPos = 0;
16479  EndElement2.ELink = EndElement2.Link[1];
16480  EndElement2.XLink = EndElement2.Link[0];
16481  if(!(EndElement2.EntryExitNumber()))
16482  {
16483  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
16484  }
16485  EndElement2.CheckCount = 9; // both now set
16486 
16487 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
16488 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
16489 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
16490 
16491  if(EndElement1.HLoc >= StartElement1.HLoc)
16492  {
16494  SearchLimitHighH = EndElement1.HLoc + 15;
16495  }
16496  else
16497  {
16498  SearchLimitLowH = EndElement1.HLoc - 15;
16500  }
16501  if(EndElement1.VLoc >= StartElement1.VLoc)
16502  {
16504  SearchLimitHighV = EndElement1.VLoc + 15;
16505  }
16506  else
16507  {
16508  SearchLimitLowV = EndElement1.VLoc - 15;
16510  }
16511 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
16512  check & TotalSearchCounts check
16513  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
16514  {
16515  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
16516  Utilities->CallLogPop(1694);
16517  return false;
16518  }
16519 */
16520 // don't need EveryPrefDir check for NonPreferredRoute
16521 
16522 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
16523 // bool InRoute = false;
16525  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16526 
16527  if(RoutePair.first > -1)
16528  {
16529  if(RoutePair.second != 0) // not first element in existing route so no good
16530  {
16531  if(!Callon)
16532  {
16533  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
16534  }
16535  Utilities->CallLogPop(275);
16536  return(false);
16537  }
16538  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
16539 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
16540  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
16541  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
16542  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16543  {
16544  if(!Callon)
16545  {
16546  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
16547  }
16548  Utilities->CallLogPop(276);
16549  return(false);
16550  }
16551  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16552  EndElement2 = BlankElement; // only need the route element
16553  EndPosition = EndElement1.TrackVectorPosition;
16554  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16555  }
16556 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16557  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16558  {
16559  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16560  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16561 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16562 // && (AdjPosition != StartRoutePosition))
16563  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16564  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16565  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16566  {
16567  if(!Callon)
16568  {
16569  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16570  }
16571  Utilities->CallLogPop(277);
16572  return(false);
16573  }
16574 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16575 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16576  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16577  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16578  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16579  (AdjPosition != StartRoutePosition))
16580  {
16581  if(!Callon)
16582  {
16583  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16584  }
16585  Utilities->CallLogPop(278);
16586  return(false);
16587  }
16588 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16590  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16591  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16592  {
16593  if(!Callon)
16594  {
16595  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16596  }
16597  Utilities->CallLogPop(279);
16598  return(false);
16599  }
16600  }
16601 
16602 // check for same route as start element
16604  {
16605  if(!Callon)
16606  {
16607  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16608  }
16609  Utilities->CallLogPop(280);
16610  return(false);
16611  }
16612 // check for a looping route
16613  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16614  {
16616  {
16617  if(!Callon)
16618  {
16619  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16620  }
16621  Utilities->CallLogPop(1845);
16622  return(false);
16623  }
16624  }
16625 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16626 // so search from this element.
16627 
16628  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16629 
16630  if(StartSelectionRouteID > -1)
16631  {
16632  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
16633  {
16635  if(PointsToBeChanged(0, NewFailedPointsTVPos))
16636  {
16637  if(NewFailedPointsTVPos > -1)
16638  {
16639  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
16640  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
16641  " failed during route setting.");
16642  Utilities->CallLogPop(2504);
16643  return(false);
16644  }
16645  PointsChanged = true;
16646  }
16647  Utilities->CallLogPop(281);
16648  return(true);
16649  }
16650  else
16651  {
16652  if(!Callon && !Track->SuppressRouteFailMessage)
16653  {
16655  }
16656  Utilities->CallLogPop(282);
16657  return(false);
16658  }
16659  }
16660  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16661  // search on the 2 ways out of the element, which has to be a 2-ended element
16662  {
16663 // check if selection adjacent to start element and if so use that
16664  if(SearchVector.at(0).Conn[0] == EndPosition)
16665  {
16666  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
16667  {
16669  if(PointsToBeChanged(1, NewFailedPointsTVPos))
16670  {
16671  if(NewFailedPointsTVPos > -1)
16672  {
16673  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
16674  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
16675  " failed during route setting.");
16676  Utilities->CallLogPop(2506);
16677  return(false);
16678  }
16679  PointsChanged = true;
16680  }
16681  Utilities->CallLogPop(283);
16682  return(true);
16683  }
16684  else
16685  {
16686  if(!Callon && !Track->SuppressRouteFailMessage)
16687  {
16689  }
16690  Utilities->CallLogPop(284);
16691  return(false);
16692  }
16693  }
16694  else if(SearchVector.at(0).Conn[1] == EndPosition)
16695  {
16696  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
16697  {
16699  if(PointsToBeChanged(2, NewFailedPointsTVPos))
16700  {
16701  if(NewFailedPointsTVPos > -1)
16702  {
16703  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
16704  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
16705  " failed during route setting.");
16706  Utilities->CallLogPop(2508);
16707  return(false);
16708  }
16709  PointsChanged = true;
16710  }
16711  Utilities->CallLogPop(285);
16712  return(true);
16713  }
16714  else
16715  {
16716  if(!Callon && !Track->SuppressRouteFailMessage)
16717  {
16719  }
16720  Utilities->CallLogPop(286);
16721  return(false);
16722  }
16723  }
16724  // now start off in the best direction
16725  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16726 
16727  if(SearchVector.at(0).Config[BestPos] != End)
16728  {
16729  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16730  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
16731  {
16733  if(PointsToBeChanged(3, NewFailedPointsTVPos))
16734  {
16735  if(NewFailedPointsTVPos > -1)
16736  {
16737  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
16738  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
16739  " failed during route setting.");
16740  Utilities->CallLogPop(2510);
16741  return(false);
16742  }
16743  PointsChanged = true;
16744  }
16745  Utilities->CallLogPop(287);
16746  return(true);
16747  }
16748  }
16749  if(SearchVector.at(0).Config[1 - BestPos] != End)
16750  {
16751  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16752  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
16753  {
16755  if(PointsToBeChanged(4, NewFailedPointsTVPos))
16756  {
16757  if(NewFailedPointsTVPos > -1)
16758  {
16759  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
16760  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
16761  " failed during route setting.");
16762  Utilities->CallLogPop(2512);
16763  return(false);
16764  }
16765  PointsChanged = true;
16766  }
16767  Utilities->CallLogPop(288);
16768  return(true);
16769  }
16770  }
16771  }
16772  if(!Callon && !Track->SuppressRouteFailMessage)
16773  {
16775  }
16776  Utilities->CallLogPop(289);
16777  return(false);
16778 }
16779 
16780 // ---------------------------------------------------------------------------
16781 
16782 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
16783 /*
16784  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16785  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16786  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16787  Keep a count of entries in SearchVector during the current function call, so that this number can be
16788  erased for an unproductive branch search.
16789  First check (within the loop) whether XLink leads to an End & return false if so.
16790  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16791  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16792  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16793  train on element (unless a bridge & train on different track), or if element
16794  fouls an existing diagonal route (except if element is a leading point - these checked later).
16795  Then check if found required element. If so save it & return true.
16796  If not the required element check if buffer or continuation, & if so erase all searchvector
16797  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16798  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16799  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16800  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16801  When return true have 8 items from CheckCount established, only waiting for EXNumber
16802 */
16803 {
16804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16805  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16806  int VectorCount = 0;
16807 
16808 // check for a fouled diagonal for first element. Added for v1.3.2
16809  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16810  (CurrentTrackElement.Link[XLinkPos] == 9))
16811  {
16812  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16813  {
16814  for(int x = 0; x < VectorCount; x++)
16815  {
16816  SearchVector.erase(SearchVector.end() - 1);
16817  }
16818  Utilities->CallLogPop(2044);
16819  return(false);
16820  }
16821  }
16822  while(true)
16823  {
16824  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16825  {
16826  for(int x = 0; x < VectorCount; x++)
16827  {
16828  SearchVector.erase(SearchVector.end() - 1);
16829  }
16830  Utilities->CallLogPop(1927);
16831  return(false);
16832  }
16833  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16834  {
16835  for(int x = 0; x < VectorCount; x++)
16836  {
16837  SearchVector.erase(SearchVector.end() - 1);
16838  }
16839  Utilities->CallLogPop(290);
16840  return(false);
16841  }
16842  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16843  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16844  TPrefDirElement SearchElement(NextTrackElement);
16845  SearchElement.TrackVectorPosition = NextPosition;
16846  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16847  SearchElement.ELinkPos = NextELinkPos;
16848  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16849  int NextXLinkPos;
16850  if(SearchElement.ELinkPos == 0)
16851  {
16852  NextXLinkPos = 1;
16853  }
16854  if(SearchElement.ELinkPos == 1)
16855  {
16856  NextXLinkPos = 0;
16857  }
16858  if(SearchElement.ELinkPos == 2)
16859  {
16860  NextXLinkPos = 3;
16861  }
16862  if(SearchElement.ELinkPos == 3)
16863  {
16864  NextXLinkPos = 2;
16865  }
16866  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16867  {
16868  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16869  // but may be buffers, continuation or gap
16870  SearchElement.XLinkPos = NextXLinkPos;
16871  }
16872 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16873 // can't set XLink or XLinkPos yet if the element is a leading point.
16874 
16875 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16876 /* drop as time consuming & RouteSearchLimit will stop search if on a loop
16877  for(unsigned int x = 0; x < SearchVector.size(); x++)
16878  {
16879  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16880  {
16881  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16882  // OK if it's a bridge & routes on different tracks
16883  {
16884  for(int x = 0; x < VectorCount; x++)
16885  {
16886  SearchVector.erase(SearchVector.end() - 1);
16887  }
16888  Utilities->CallLogPop(291);
16889  return(false);
16890  }
16891  }
16892  }
16893 */
16894 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16895  TAllRoutes::TRouteElementPair SecondPair;
16897  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16898  if(RoutePair.first > -1)
16899  {
16900  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16901  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16902  RoutePair.second).ELinkPos)))
16903  {
16904  // still OK if start of an expected route
16905  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16906  {
16907  for(int x = 0; x < VectorCount; x++)
16908  {
16909  SearchVector.erase(SearchVector.end() - 1);
16910  }
16911  Utilities->CallLogPop(292);
16912  return(false); // only allow for start of an expected route
16913  }
16914  }
16915  }
16916  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16917  {
16918  // OK if it's a bridge & routes on different tracks
16919  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16920  SecondPair.second).ELinkPos)))
16921  {
16922  // still OK if start of an expected route
16923  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16924  {
16925  for(int x = 0; x < VectorCount; x++)
16926  {
16927  SearchVector.erase(SearchVector.end() - 1);
16928  }
16929  Utilities->CallLogPop(293);
16930  return(false); // only allow for start of an expected route
16931  }
16932  }
16933  }
16934 // check if a train on element, unless a bridge & train on different track
16935 // OK of same train as start element - no, drop this
16936 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16937  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16938  {
16939  for(int x = 0; x < VectorCount; x++)
16940  {
16941  SearchVector.erase(SearchVector.end() - 1);
16942  }
16943  Utilities->CallLogPop(294);
16944  return(false);
16945  }
16946  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16947  {
16948  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16949  {
16950  for(int x = 0; x < VectorCount; x++)
16951  {
16952  SearchVector.erase(SearchVector.end() - 1);
16953  }
16954  Utilities->CallLogPop(295);
16955  return(false);
16956  }
16957  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16958  {
16959  for(int x = 0; x < VectorCount; x++)
16960  {
16961  SearchVector.erase(SearchVector.end() - 1);
16962  }
16963  Utilities->CallLogPop(296);
16964  return(false);
16965  }
16966  }
16967 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16968  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16969  {
16970  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16971  {
16972  for(int x = 0; x < VectorCount; x++)
16973  {
16974  SearchVector.erase(SearchVector.end() - 1);
16975  }
16976  Utilities->CallLogPop(297);
16977  return(false);
16978  }
16979  }
16980 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16981 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16982 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16984  {
16985  for(int x = 0; x < VectorCount; x++)
16986  {
16987  SearchVector.erase(SearchVector.end() - 1);
16988  }
16989  Utilities->CallLogPop(1689);
16990  return(false);
16991  }
16992 // check if found it
16993  if(SearchElement.TrackVectorPosition == RequiredPosition)
16994  {
16995  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16996  {
16997  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16998  {
16999  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17000  }
17001  else
17002  {
17003  SearchElement.XLinkPos = 1;
17004  }
17005 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17006  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17007  }
17008  SearchVector.push_back(SearchElement);
17009  VectorCount++; // not really needed but include for tidyness
17010  TotalSearchCount++;
17011  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17012  {
17013  for(int x = 0; x < VectorCount; x++)
17014  {
17015  SearchVector.erase(SearchVector.end() - 1);
17016  }
17017  Utilities->CallLogPop(2525);
17018  return(false);
17019  }
17020  Utilities->CallLogPop(298);
17021  return(true);
17022  }
17023 // Not the required element - check if a buffer or continuation
17024  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17025  {
17026  for(int x = 0; x < VectorCount; x++)
17027  {
17028  SearchVector.erase(SearchVector.end() - 1);
17029  }
17030  Utilities->CallLogPop(299);
17031  return(false);
17032  }
17033 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17035  {
17036  for(int x = 0; x < VectorCount; x++)
17037  {
17038  SearchVector.erase(SearchVector.end() - 1);
17039  }
17040  Utilities->CallLogPop(1421);
17041  return(false);
17042  }
17043 //deal with failed points, added at v2.13.0
17044  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17045  {
17046  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17047  {
17048  SearchElement.XLinkPos = 1;
17049  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17050  }
17051  else
17052  {
17053  SearchElement.XLinkPos = 3;
17054  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17055  }
17056  }
17057  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17058  {
17059  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17060  {
17061  for(int x = 0; x < VectorCount; x++)
17062  {
17063  SearchVector.erase(SearchVector.end() - 1);
17064  }
17065  Utilities->CallLogPop(2533);
17066  return(false);
17067  }
17068  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17069  {
17070  for(int x = 0; x < VectorCount; x++)
17071  {
17072  SearchVector.erase(SearchVector.end() - 1);
17073  }
17074  Utilities->CallLogPop(2534);
17075  return(false);
17076  }
17077  }
17078 
17079 // check if reached a non-failed leading point
17080  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17081  { //added !Failed condition at v2.13.0 to exclude failed points
17082 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17083  int SearchPos1 = SearchElement.Attribute + 1;
17084  int SearchPos2;
17085  if(SearchPos1 == 2)
17086  {
17087  SearchPos1++;
17088  }
17089  if(SearchPos1 == 1)
17090  {
17091  SearchPos2 = 3;
17092  }
17093  else
17094  {
17095  SearchPos2 = 1;
17096  }
17097 // push element with XLink set to position [SearchPos1]
17098  SearchElement.XLink = SearchElement.Link[SearchPos1];
17099  SearchElement.XLinkPos = SearchPos1;
17100 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17101  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17102  {
17103  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17104  {
17105  for(int x = 0; x < VectorCount; x++)
17106  {
17107  SearchVector.erase(SearchVector.end() - 1);
17108  }
17109  Utilities->CallLogPop(300);
17110  return(false);
17111  }
17112  }
17113  SearchVector.push_back(SearchElement);
17114  VectorCount++;
17115  TotalSearchCount++;
17116 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17117 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17118 // recursive search as has to be a TTrackElement for non-preferred route searches
17119  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17120  {
17121  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17122  {
17123  for(int x = 0; x < VectorCount; x++)
17124  {
17125  SearchVector.erase(SearchVector.end() - 1);
17126  }
17127  Utilities->CallLogPop(2526);
17128  return(false);
17129  }
17130  Utilities->CallLogPop(301);
17131  return(true);
17132  }
17133  else
17134  {
17135 // remove leading point with XLinkPos [SearchPos1]
17136  SearchVector.erase(SearchVector.end() - 1);
17137  VectorCount--;
17138 // push element with XLink set to position [SearchPos2]
17139  SearchElement.XLink = SearchElement.Link[SearchPos2];
17140  SearchElement.XLinkPos = SearchPos2;
17141 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17142  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17143  {
17144  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17145  {
17146  for(int x = 0; x < VectorCount; x++)
17147  {
17148  SearchVector.erase(SearchVector.end() - 1);
17149  }
17150  Utilities->CallLogPop(302);
17151  return(false);
17152  }
17153  }
17154  SearchVector.push_back(SearchElement);
17155  VectorCount++;
17156  TotalSearchCount++;
17157 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17158  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17159  {
17160  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17161  {
17162  for(int x = 0; x < VectorCount; x++)
17163  {
17164  SearchVector.erase(SearchVector.end() - 1);
17165  }
17166  Utilities->CallLogPop(2527);
17167  return(false);
17168  }
17169  Utilities->CallLogPop(303);
17170  return(true);
17171  }
17172  else
17173  {
17174  for(int x = 0; x < VectorCount; x++)
17175  {
17176  SearchVector.erase(SearchVector.end() - 1);
17177  }
17178  Utilities->CallLogPop(304);
17179  return(false);
17180  }
17181  }
17182  } // if leading point
17183 
17184 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17185 // ready for next element on route
17186  SearchVector.push_back(SearchElement);
17187  VectorCount++;
17188  TotalSearchCount++;
17189  CurrentTrackElement = SearchElement;
17190  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17191  } // while(true)
17192 }
17193 
17194 // ---------------------------------------------------------------------------
17195 
17197 
17198 /*
17199  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17200  having all values set (since not necessarily on PrefDirs).
17201  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17202  (if it was the start), so these are checked first and set if necessary. All elements now have
17203  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17204  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17205  to set the route colour and direction graphics.
17206 */
17207 
17208 {
17209  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17210  if(SearchVector.size() == 0)
17211  {
17212  throw Exception("Error, SearchVector empty");
17213  }
17214 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17215 // hence need to examine and update it if necessary
17216  TPrefDirElement SecondElement;
17217 
17218  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17219  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17220  // need above check or SecondElement will fail
17221  {
17222  SecondElement = SearchVector.at(1);
17223  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17224  for(int x = 0; x < 4; x++)
17225  {
17226  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17227  {
17228  if(SearchVector.at(0).XLink == -1) // i.e. not set
17229  {
17230  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17231  SearchVector.at(0).XLinkPos = x;
17232  }
17233  int ELinkPos;
17234  if(SearchVector.at(0).XLinkPos == 0)
17235  {
17236  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17237  }
17238  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17239  if(SearchVector.at(0).XLinkPos == 1)
17240  {
17241  ELinkPos = 0;
17242  }
17243  if(SearchVector.at(0).XLinkPos == 2)
17244  {
17245  ELinkPos = 3;
17246  }
17247  if(SearchVector.at(0).XLinkPos == 3)
17248  {
17249  ELinkPos = 2;
17250  }
17251  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17252  {
17253  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17254  SearchVector.at(0).ELinkPos = ELinkPos;
17255  }
17256  break; // no point going any further
17257  }
17258  }
17259  }
17260  for(unsigned int x = 0; x < SearchVector.size(); x++)
17261  {
17262  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17263 // set EXNumber
17264  if(!(SearchVector.at(x).EntryExitNumber()))
17265  {
17266  throw Exception("Error in EntryExitNumber 3");
17267  }
17268  SearchVector.at(x).CheckCount++;
17269 // all values now incorporated
17270  }
17271 
17272  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17273 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17274 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17275  Utilities->CallLogPop(305);
17276 }
17277 
17278 // ---------------------------------------------------------------------------
17279 
17281 
17282 /*
17283  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17284  AutoSigsRoute.
17285  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17286  beginning or the end.
17287  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17288  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17289  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17290  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17291  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17292  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17293  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17294 
17295  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17296  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17297  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17298  route at the start.
17299 
17300  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17301  for the new route and return.
17302 */
17303 
17304 {
17305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17306  AnsiString(ReqPosRouteID.GetInt()));
17307  if(SearchVector.size() < 1)
17308  {
17309  Utilities->CallLogPop(306);
17310  return;
17311  }
17312  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17313  if(!ValidatePrefDir(6))
17314  {
17315  Utilities->CallLogPop(307);
17316  return;
17317  }
17318  TAllRoutes::TLockedRouteClass LockedRouteObject;
17319 
17321  unsigned int TruncatePrefDirPosition = 0;
17322 
17323  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17324 /* if have ReqPosRouteID:
17325  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17326  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17327  then enter the new route into the AllRoutesVector
17328 */
17329  {
17331  {
17332  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17333  x++) // start at 1 as first element already in SearchVector
17334  {
17336  }
17337  // note that route numbers in map adjusted when ReqPos route cleared
17339  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17340  // set during ClearRouteDuringRouteBuildingAt)
17342  {
17345  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17346  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17347  }
17348  }
17350  {
17351  SearchVector.pop_back();
17352  }
17353  }
17354  if(StartSelectionRouteID > -1)
17355 /* if have StartSelectionRouteID:
17356  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17357  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17358 */
17359  {
17361  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17362  {
17364  {
17365  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17366  for(unsigned int x = 0; x < SearchVector.size(); x++)
17367  {
17369  RouteNumber, GetFixedSearchElementAt(7, x));
17370  // find & store locked route truncate position in PrefDirVector for later use
17372  {
17373  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17374  {
17375  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17376  }
17377  }
17378  }
17380  {
17381  throw Exception("Failed to validate extended route for nonpreferred route");
17382  }
17385  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17386  // now add the reinstated locked route if required and set signals accordingly
17387  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17388  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17389  // that I haven't thought of
17391  {
17392  LockedRouteObject.RouteNumber = RouteNumber;
17393  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17394  // now reset the signals for the locked route
17395  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17396  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17397  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17398  {
17399  // return all signals to red in route section to be truncated
17400  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17401  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17402  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17403  {
17404  TrackElement.Attribute = 0;
17405  Track->PlotSignal(11, TrackElement, Display);
17406  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17407  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17408  }
17409  }
17410  }
17411  AllRoutes->CheckMapAndRoutes(3); // test
17412  Utilities->CallLogPop(308);
17413  return;
17414  }
17415  }
17416  else
17417  {
17419  }
17420 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17421 // hence nothing to do here
17422  }
17423  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17424  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17425  {
17426  throw Exception("Failed to validate single route for nonpreferred route");
17427  }
17428  AllRoutes->StoreOneRoute(2, this);
17429  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
17430  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
17431  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
17432  AllRoutes->CheckMapAndRoutes(4); // test
17433  Utilities->CallLogPop(309);
17434 }
17435 
17436 // ---------------------------------------------------------------------------
17437 
17438 void TOneRoute::SetRoutePoints(int Caller) const
17439 /*
17440  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
17441  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
17442  when they were created.
17443 */
17444 {
17445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
17446  if(!PrefDirVector.empty())
17447  {
17448  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17449  {
17450  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
17451  {
17452  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
17453  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
17454  }
17455  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
17456  {
17457  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
17458  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
17459  }
17460  }
17461  }
17462  Utilities->CallLogPop(327);
17463 }
17464 
17465 // ---------------------------------------------------------------------------
17466 
17467 void TOneRoute::SetRouteSignals(int Caller) const
17468 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
17469 
17470 {
17471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
17472  if(!PrefDirVector.empty())
17473  {
17474  int RouteNumber;
17475  int Attribute = 0;
17476  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
17477  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
17478  if(RouteType != TAllRoutes::NoRoute)
17479  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
17480  {
17481  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
17482  }
17483  }
17484  Utilities->CallLogPop(1720);
17485 }
17486 
17487 // ---------------------------------------------------------------------------
17488 
17489 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
17490 {
17491  //true if at any point in SearchVector points have to be changed,
17492  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
17493  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
17494  NewFailedPointsTVPos = -1; //default value for no new failure
17495  bool PointsChanged = false;
17496  if(!SearchVector.empty())
17497  {
17498  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
17499  {
17500  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
17501  //check for an existing failed point where needs to change to make the route
17502  int Attr = TE.Attribute;
17503  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
17504  {
17505  if(Attr == 1) //currently set to diverge
17506  {
17507  //here add new failure possibility at v2.13.0
17508  if(Utilities->FailureMode != FNil)
17509  {
17510  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17511  {
17513  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17514  IFE.TVPos = NewFailedPointsTVPos;
17515  TE.Failed = true;
17516  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17518  TE.SpeedLimit01 = 10; //values while failed
17519  TE.SpeedLimit23 = 10;
17520  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17521  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17522  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17523  //set repair time, random value in minutes between 10 and 179
17524  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
17525  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17526  IFE.RepairTime = RepairTime;
17528  Track->FailedPointsVector.push_back(IFE);
17529  Utilities->CallLogPop(1717);
17530  return(true); //return so only allow one failure per route
17531  }
17532  }
17533  PointsChanged = true; //this is used for setting the flash time
17534  }
17535  }
17536  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
17537  {
17538  if(Attr == 0) //currently set to go straight
17539  {
17540  //here add failure possibility at v2.13.0
17541  if(Utilities->FailureMode != FNil)
17542  {
17543  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17544  {
17546  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17547  IFE.TVPos = NewFailedPointsTVPos;
17548  TE.Failed= true;
17549  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17551  TE.SpeedLimit01 = 10; //values while failed
17552  TE.SpeedLimit23 = 10;
17553  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17554  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17555  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17556  //set repair time, random value in minutes between 10 and 179
17557  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
17558  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17559  IFE.RepairTime = RepairTime;
17561  Track->FailedPointsVector.push_back(IFE);
17562  Utilities->CallLogPop(1718);
17563  return(true); //only allow one failure per route
17564  }
17565  }
17566  PointsChanged = true;
17567  }
17568  }
17569  }
17570  }
17571  Utilities->CallLogPop(1719);
17572  return(PointsChanged);
17573 }
17574 
17575 // ---------------------------------------------------------------------------
17576 
17577 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
17578 /* //added StartPos at v2.17.0 so it starts in the current route
17579 
17580  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
17581 
17582  Works forward through the route from & including StartPos until finds:-
17583  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17584  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
17585  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
17586  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17587  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
17588  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17589  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
17590  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17591  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
17592 */
17593 {
17594  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
17595  Attribute = 0;
17596  NextForwardLinkedRouteNumber = -1;
17597  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
17598  {
17599  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
17600  if(PrefDirVector.at(x).TrackType == Bridge)
17601  {
17602  if(PrefDirVector.at(x).XLinkPos < 2)
17603  {
17604  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17605  }
17606  else
17607  {
17608  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17609  }
17610  }
17611  if(TrainID != -1)
17612  {
17613  Utilities->CallLogPop(328); //attribute still 0
17614  return(true);
17615  }
17616  if(PrefDirVector.at(x).TrackType == Buffers)
17617  {
17618  Attribute = 1;
17619  Utilities->CallLogPop(329);
17620  return(true);
17621  }
17622  if(PrefDirVector.at(x).TrackType == Continuation)
17623  {
17624  Attribute = 3;
17625  Utilities->CallLogPop(330);
17626  return(true);
17627  }
17628  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17629  {
17630  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17631  {
17632  Attribute = 0;
17633  Utilities->CallLogPop(1950);
17634  return(true);
17635  }
17636  }
17637  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
17638  {
17639  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
17640  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
17641  {
17642  Attribute++;
17643  }
17644  if(Attribute > 3)
17645  {
17646  Attribute = 3;
17647  }
17648  Utilities->CallLogPop(331);
17649  return(true);
17650  }
17651  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
17652  {
17653  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
17654  NextForwardLinkedRouteNumber = -1;
17655  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
17656 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
17657  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
17658  {
17659  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
17660  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
17661  {
17662  Attribute = 0;
17663  Utilities->CallLogPop(332);
17664  return(false);
17665  }
17666  //else there is no forward route, so return true with attribute still 0
17667  }
17668  //else there is no forward route, so return true with attribute still 0
17669  }
17670  }
17671  Utilities->CallLogPop(333); //
17672  return(true);
17673 }
17674 
17675 // ---------------------------------------------------------------------------
17676 
17677 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
17678 /* Major changes at v2.17.0
17679  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17680 
17681  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17682  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17683  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
17684  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
17685  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
17686  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
17687  or (c) truncating a route.
17688 
17689  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17690  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
17691  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
17692  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
17693  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
17694  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
17695  the function returns true.
17696 
17697  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
17698  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17699 */
17700 {
17701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
17702  AnsiString(PrefDirVectorStartPosition));
17703  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17704  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17705 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17706 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17707 
17708  if(!PrefDirVector.empty())
17709  {
17710  if(!SkipForwardLook)
17711  {
17712  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17713  {
17714  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17715  if(PrefDirPtr->TrackType == Bridge)
17716  {
17717  if(PrefDirPtr->XLinkPos < 2)
17718  {
17719  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17720  }
17721  else
17722  {
17723  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17724  }
17725  }
17726  if(TrainID != -1)
17727  {
17728  SkipForwardLook = true;
17729  break;
17730  }
17731  }
17732  }
17733 
17735  {
17736  SkipForwardLook = true;
17737  }
17738 
17739  int NextForwardLinkedRouteNumber = -1;
17740  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
17741  {
17742  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
17744 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
17745  if(RouteType == TAllRoutes::NoRoute)
17746  {
17747  SkipForwardLook = true; //if there's no linked forward route then skip
17748  if(PrefDirVector.back().TrackType == Buffers)
17749  {
17750  Attribute = 1; // treat buffer as red signal
17751  }
17752  if(PrefDirVector.back().TrackType == Continuation)
17753  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
17754  bool SetAttributeTo3 = true;
17757  {
17758  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17759  AutoSigVectorIT++)
17760  {
17761  if(!AllRoutes->AllRoutesVector.empty())
17762  {
17763  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17764  {
17765  SetAttributeTo3 = false;
17766  Attribute = AutoSigVectorIT->AccessNumber;
17767  break;
17768  }
17769  }
17770  }
17771  }
17772  if(SetAttributeTo3)
17773  {
17774  Attribute = 3; // treat continuation as a green signal
17775  }
17776  }
17777  }
17778  else //startpos still on end element and there is probably a forward route
17779  {
17780  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
17781  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
17782  {
17783  SkipForwardLook = true; //if there's no linked forward route then skip
17784  if(PrefDirVector.back().TrackType == Buffers)
17785  {
17786  Attribute = 1; // treat buffer as red signal
17787  }
17788  if(PrefDirVector.back().TrackType == Continuation)
17789  {
17790  Attribute = 3; // treat continuation as a green signal
17791  }
17792  }
17793  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
17794  }
17795  }
17796 
17797  if(!SkipForwardLook)
17798  {
17799  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
17800  //SkipForwardLook will be true - see above)
17801  int StartPos;
17802  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
17803  {
17804  StartPos = PrefDirVectorStartPosition + 1;
17805  }
17806  else
17807  {
17808  StartPos = 0; //start of next forward route
17809  }
17810  if(StartPos > 0) //starting in this route
17811  {
17812  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
17813  {
17814  StartPos = 0; //reset to 0 for next route
17815  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
17816  {
17817  continue;
17818  }
17819  }
17820  }
17821  else //starting in next forward route
17822  {
17823  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
17824  {
17825  continue;
17826  }
17827  }
17828  }
17829 
17830  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
17831  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17832  {
17833  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17834  if(PrefDirPtr->TrackType == Bridge)
17835  {
17836  if(PrefDirPtr->XLinkPos < 2)
17837  {
17838  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17839  }
17840  else
17841  {
17842  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17843  }
17844  }
17845  if(TrainID != -1)
17846  {
17847  Utilities->CallLogPop(334);
17848  return(false);
17849  }
17850  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17851  // the attribute to 0 so first signal behind the LC is red
17852  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17853  {
17854  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17855  {
17856  Attribute = 0;
17857  }
17858  }
17859 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17860 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17861  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17862  {
17863  if((!AllRoutes->RouteBackTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17864  PrefDirPtr->PrefDirRoute)
17865  {
17866 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17867 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17868  int LockedVecNum = 0; //not used
17869  TPrefDirElement DummyPrefDir; //not used
17870  bool KeepAttributeAt0ForLockedRoute = false;
17871  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17872  LockedVecNum))
17873  {
17874  Attribute = 0;
17875  KeepAttributeAt0ForLockedRoute = true;
17876  }
17877 //end of v2.9.2 addition
17878 
17879 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
17880  bool NotGroundSignal = false;
17881  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
17882  {
17883  NotGroundSignal = true;
17884  }
17885 
17886  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
17887  {
17888  Attribute = 0; //stays at 0
17889  }
17890 
17891  if(Attribute < 3)
17892  {
17893  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17894  }
17895  else
17896  {
17897  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17898  }
17899  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17900  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17901  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17902  {
17903  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17904  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17905  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17906  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17907  }
17908  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
17909  { //if groundsignal attrib is 0 then do need to increment
17910  Attribute++; //this is for the next signal rearwards, not the current one
17911  }
17912 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
17913  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
17914  }
17915  }
17916  }
17917  }
17918  Utilities->CallLogPop(335);
17919  return(true);
17920 }
17921 
17922 // ---------------------------------------------------------------------------
17923 
17924 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17925 /*
17926  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17927  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17928  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17929  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17930  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17931  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17932  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17933  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17934 */
17935 {
17936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17937  "," + AnsiString((short)PrefDirRoute));
17938  bool ElementInRoute = false;
17939  bool MovingTrainOccupyingRoute = false;
17940  unsigned int TruncatePDElementPos; //the selected PD position to truncate to (could be from the back or the front)//added at v2.15.0
17941  enum {NoTruncate, BackTruncate, FrontTruncate, FullTruncate} TruncateType;
17942  TruncateType = NoTruncate;
17944 
17945  for(unsigned int b = 0; b < PrefDirSize(); b++)
17946  {
17947  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17948  {
17949  TruncatePDElementPos = b;
17950  ElementInRoute = true;
17951  break;
17952  }
17953  }
17954  if(!ElementInRoute)
17955  {
17956  ReturnFlag = NotInRoute;
17957  Utilities->CallLogPop(336);
17958  return;
17959  }
17960 
17961  //now find whether back, front or full truncate //added at v2.15.0
17962  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate
17963  {
17964  if(TruncatePDElementPos == 0)
17965  {
17966  TruncateType = FullTruncate;
17967  AllRoutes->RouteBackTruncateFlag = true; //Added at v2.15.1: FullTruncate is also a form of BackTruncate as far as the flag is concerned for SetAllRearwardsSignals
17968  } //without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
17969  else //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
17970  { //truncate for that route), the last signal in the autosigs route doesn't change to red.
17971  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
17972  if(TempElement.Config[TempElement.XLinkPos] == Signal)
17973  {
17974  TruncateType = FrontTruncate;
17975  }
17976  else
17977  {
17978  TruncateType = BackTruncate;
17980  }
17981  }
17982  }
17983  else // == PrefDirSize() - 1
17984  {
17985  TruncateType = BackTruncate;
17987  }
17988 
17989 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
17990 
17991  if(TruncateType == BackTruncate) //added at v2.15.0
17992  {
17993  for(int b = PrefDirSize() - 1; b >= 0; b--)
17994  {
17995  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17996  if(PrefDirVector.at(b).TrackType == Bridge)
17997  {
17998  if(PrefDirVector.at(b).XLinkPos < 2)
17999  {
18000  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18001  }
18002  else
18003  {
18004  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18005  }
18006  }
18007  if(TrainID != -1)
18008  {
18009  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18010  {
18011  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18012  }
18013  }
18014  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18015  {
18016  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18017  ReturnFlag = InRouteFalse;
18019  Utilities->CallLogPop(1941);
18020  return;
18021  }
18022  if(b == int(TruncatePDElementPos))
18023  {
18024  break; // OK found truncate element & no flashing LC in front
18025  }
18026  }
18027  }
18028  else if(TruncateType == FrontTruncate)//front/full truncate //added at v2.15.0
18029  {
18030  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
18031  {
18032  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18033  if(PrefDirVector.at(b).TrackType == Bridge)
18034  {
18035  if(PrefDirVector.at(b).XLinkPos < 2)
18036  {
18037  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18038  }
18039  else
18040  {
18041  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18042  }
18043  }
18044  if(TrainID != -1)
18045  {
18046  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
18047  {
18048  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18049  }
18050  }
18051  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18052  {
18053  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
18054  ReturnFlag = InRouteFalse;
18056  Utilities->CallLogPop(2571);
18057  return;
18058  }
18059  if(b == TruncatePDElementPos)
18060  {
18061  break; // OK found truncate element & no flashing LC behind
18062  }
18063  }
18064  }
18065  else //FullTruncate) //added at v2.15.0
18066  {
18067  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
18068  {
18069  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18070  if(PrefDirVector.at(b).TrackType == Bridge)
18071  {
18072  if(PrefDirVector.at(b).XLinkPos < 2)
18073  {
18074  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18075  }
18076  else
18077  {
18078  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18079  }
18080  }
18081  if(TrainID != -1)
18082  {
18083  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
18084  {
18085  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18086  }
18087  }
18088  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18089  {
18090  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
18091  ReturnFlag = InRouteFalse;
18093  Utilities->CallLogPop(2572);
18094  return;
18095  }
18096  }
18097  }
18098 
18099  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
18100  {
18101  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
18102  ReturnFlag = InRouteFalse;
18104  Utilities->CallLogPop(338);
18105  return;
18106  }
18107  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
18108  {
18109  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
18110  ReturnFlag = InRouteFalse;
18112  Utilities->CallLogPop(339);
18113  return;
18114  }
18115 
18116  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
18117  {
18118  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
18119  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18120  {
18121  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18122  {
18123  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18124  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18125  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18126  ReturnFlag = InRouteFalse;
18128  Utilities->CallLogPop(340);
18129  return;
18130  }
18131  }
18132  else
18133  {
18134  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18135  {
18136  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
18137  ReturnFlag = InRouteFalse;
18139  Utilities->CallLogPop(341);
18140  return;
18141  }
18142  }
18143  }
18144 
18145  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
18146  {
18147  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
18148  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18149  {
18150  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18151  {
18152  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18153  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18154  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18155  ReturnFlag = InRouteFalse;
18157  Utilities->CallLogPop(2573);
18158  return;
18159  }
18160  }
18161  else //red route
18162  {
18163  if(TruncatePDElementPos > 0)
18164  {
18165  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
18166  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18167  {
18168  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
18169  ReturnFlag = InRouteFalse;
18171  Utilities->CallLogPop(2574);
18172  return;
18173  }
18174  }
18175  }
18176  }
18177 
18178  else if(TruncatePDElementPos == 0) //full truncate
18179  {
18180  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
18181  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
18182  {
18183  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
18184  {
18185  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18186  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18187  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18188  ReturnFlag = InRouteFalse;
18190  Utilities->CallLogPop(2575);
18191  return;
18192  }
18193  }
18194  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
18195  {
18196  if(TempElement.TrackType == Bridge)
18197  {
18198  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
18199  ReturnFlag = InRouteFalse;
18201  Utilities->CallLogPop(2576);
18202  return;
18203  }
18204  }
18205  }
18206 
18207  int ThisRouteNumber;
18209 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
18210 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
18211 
18212 // check if part of this route already locked & disallow if so
18213  if(!(AllRoutes->LockedRouteVector.empty()))
18214  {
18216  {
18217  if(LRVIT->RouteNumber == ThisRouteNumber)
18218  {
18219  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
18220  ReturnFlag = InRouteFalse;
18222  Utilities->CallLogPop(749);
18223  return;
18224  }
18225  }
18226  }
18227 
18228  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
18229  if(TruncateType == BackTruncate) //is within 3 running signals on this or linked rearwards routes -m this is a PDElement position
18230  {
18231  LookBackwardsFromHere = TruncatePDElementPos;
18232  }
18233 
18234 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
18235  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
18236  int FrontPosition;
18237 
18238  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
18239  // RouteLockingRequired only checks for trains approaching
18240  {
18243  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
18244  L"Warning!", MB_YESNO | MB_ICONWARNING);
18245  TrainController->BaseTime = TDateTime::CurrentDateTime();
18247  if(button == IDNO)
18248  {
18249  ReturnFlag = InRouteTrue; // still return true even though don't act on it
18251  Utilities->CallLogPop(342);
18252  return;
18253  }
18254  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
18255  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
18256  TAllRoutes::TLockedRouteClass LockedRoute;
18257  bool ExistingLockedRouteModified = false;
18258  LockedRoute.RouteNumber = ThisRouteNumber;
18259  if(TruncateType == BackTruncate)
18260  {
18261  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18262  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18263  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18264  }
18265  else if(TruncateType == FrontTruncate)
18266  {
18267  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18268  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18269  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
18270  }
18271  else //FullTruncate
18272  {
18273  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18274  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18275  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18276  }
18277 
18278  LockedRoute.LockStartTime = TrainController->TTClockTime;
18279 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
18280 // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
18281  if(!AllRoutes->LockedRouteVector.empty())
18282  {
18283  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
18284  LRVIT++)
18285  {
18286  if(LRVIT->RouteNumber == ThisRouteNumber)
18287  {
18288  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
18289  LRVIT->LockStartTime = LockedRoute.LockStartTime;
18290  ExistingLockedRouteModified = true;
18291  }
18292  }
18293  }
18294  if(!ExistingLockedRouteModified)
18295  {
18296  AllRoutes->LockedRouteVector.push_back(LockedRoute);
18297  }
18298  if(TruncateType == BackTruncate)
18299  {
18300  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
18301  RearPosition = TruncatePDElementPos;
18302  FrontPosition = PrefDirSize() - 1;
18303  }
18304  else if(TruncateType == FrontTruncate)
18305  {
18306  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
18307  RearPosition = 0;
18308  FrontPosition = TruncatePDElementPos;
18309  }
18310  else //FullTruncate
18311  {
18312  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
18313  RearPosition = 0;
18314  FrontPosition = PrefDirSize() - 1;
18315  }
18316 // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
18317  for(int c = FrontPosition; c >= RearPosition; c--)
18318  {
18319  // return all signals to red in route section to be truncated
18320  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
18321  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
18322  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18323  {
18324  TrackElement.Attribute = 0;
18325  Track->PlotSignal(2, TrackElement, Display);
18326  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18327  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18328  }
18329  }
18330 // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
18331  ReturnFlag = InRouteTrue;
18332  }
18333  else //route locking not required
18334  {
18335  if(TruncateType == BackTruncate)
18336  {
18337  RearPosition = TruncatePDElementPos;
18338  FrontPosition = PrefDirSize() - 1;
18339  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
18340  }
18341  else if(TruncateType == FrontTruncate)
18342  {
18343  RearPosition = 0;
18344  FrontPosition = TruncatePDElementPos;
18345  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
18346  }
18347  else
18348  {
18349  RearPosition = 0;
18350  FrontPosition = PrefDirSize() - 1;
18351  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
18352  }
18353 
18354  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
18355  //into adjacent red or green routes if there are any (after the truncation/removal)
18356 
18357  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18358  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
18359 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
18360 
18361  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
18362  {
18363  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
18364  ReturnFlag = InRouteTrue;
18365  }
18366 
18367  if(LastPDElement.AutoSignals)
18368  {
18369  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
18370  }
18371  }
18372 
18373  AllRoutes->CheckMapAndRoutes(5); // test
18374  ReturnFlag = InRouteTrue;
18376  Utilities->CallLogPop(344);
18377 }
18378 
18379 // ---------------------------------------------------------------------------
18380 
18382 {
18383 /*
18384 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
18385 signal.
18386 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
18387  but a new route that is created TO a signal - that signal becomes part of the new route.
18388 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
18389 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
18390  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
18391  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
18392  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
18393  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
18394  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
18395 */
18396 
18397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
18398  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
18399  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
18400  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
18401  {
18402  Utilities->CallLogPop(2578);
18403  return;
18404  }
18405  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
18406  int RouteColour;
18407  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
18408  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18409  {
18410  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
18411  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
18412  { //found a linked forward route
18413  //check if signal behind this route has been removed from the blue route
18414  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18415  { //signal needs to be added at start of this linked route
18416 
18417  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
18418  if(RouteColour == 1) //red route
18419  {
18420  NewRedFirstPDElement = LastPDElement;
18421  NewRedFirstPDElement.AutoSignals = false;
18422  NewRedFirstPDElement.PrefDirRoute = false;
18423  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18424  NewRedFirstPDElement.IsARoute = true;
18425  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
18426  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
18427  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
18428  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
18429  {
18430  if(R2MMIt->second.first == int(x))
18431  {
18432  R2MMIt->second.second++;
18433  }
18434  }
18435  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
18436  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18437  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
18438  }
18439  else if(RouteColour == 2) //green route
18440  {
18441  NewGreenFirstPDElement = LastPDElement;
18442  NewGreenFirstPDElement.AutoSignals = false;
18443  NewGreenFirstPDElement.PrefDirRoute = true;
18444  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
18445  NewGreenFirstPDElement.IsARoute = true;
18446  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
18447  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
18448  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
18449  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
18450  {
18451  if(R2MMIt->second.first == int(x))
18452  {
18453  R2MMIt->second.second++;
18454  }
18455  }
18456  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
18457  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18458  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
18459  }
18460  }
18461  break; //no point looking any further
18462  }
18463  }
18464 
18465 //check if there's a linked rearward route missing a signal and if so add it
18466  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18467  {
18468  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
18469  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
18470  { //found a linked rearward route
18471  //check if signal in front of this route has been removed from the blue route
18472  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18473  { //signal needs to be added at end of this linked route
18474 
18475  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
18476  if(RouteColour == 1) //red route
18477  {
18478  NewRedLastPDElement = FirstPDElement;
18479  NewRedLastPDElement.AutoSignals = false;
18480  NewRedLastPDElement.PrefDirRoute = false;
18481  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18482  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
18483  //can use this as adding to the end of the route
18484  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18485  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
18486  }
18487  else if(RouteColour == 2) //green route
18488  {
18489  NewGreenLastPDElement = FirstPDElement;
18490  NewGreenLastPDElement.AutoSignals = false;
18491  NewGreenLastPDElement.PrefDirRoute = true;
18492  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
18493  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
18494  //can use this as adding to the end of the route
18495  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
18496  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
18497  }
18498  }
18499  break; //no point looking any further
18500  }
18501  }
18502  Utilities->CallLogPop(2579);
18503 }
18504 
18505 // ---------------------------------------------------------------------------
18506 
18508 /*
18509  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
18510  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
18511  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
18512  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
18513  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
18514  the route colours.
18515 */
18516 {
18517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
18518  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
18520  int RouteNumber;
18521  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
18522  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
18523  //these added at v2.15.0
18524  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18525  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
18526 
18527  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
18528  {
18529  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
18530  {
18531  if(PrefDirVector.at(x).TrackType == SignalPost)
18532  {
18533  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
18534  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
18535  }
18536  }
18537 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
18538  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
18539  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
18540  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
18541  //when should have been be red.
18542 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
18543  }
18544  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
18545  {
18546  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
18547  }
18548 
18549  if(LastPDElement.AutoSignals) //added at v2.15.0
18550  {
18551  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
18552  }
18553 
18554  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
18555  {
18556  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
18557  {
18558  ARVIt->SetRouteSignals(14);
18559  }
18560  }
18561  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
18562  AllRoutes->CheckMapAndRoutes(9); // test
18563  TrainController->BaseTime = TDateTime::CurrentDateTime();
18565  Utilities->CallLogPop(345);
18566  return;
18567 }
18568 
18569 // ---------------------------------------------------------------------------
18570 
18571 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18572 /*
18573  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
18574 */
18575 {
18576  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
18577  AnsiString((short)PrefDirRoute));
18578  if(SearchVector.empty())
18579  {
18580  Utilities->CallLogPop(1149);
18581  return;
18582  }
18583  for(unsigned int b = 0; b < SearchVector.size(); b++)
18584  {
18587  PrefDirRoute);
18588  }
18589  Utilities->CallLogPop(346);
18590 }
18591 
18592 // ---------------------------------------------------------------------------
18593 
18594 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18595 /*
18596  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
18597  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
18598  TOneRoute.
18599 */
18600 {
18601  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
18602  AnsiString((short)PrefDirRoute));
18603  RouteFlash.RouteFlashVector.clear();
18604  TRouteFlashElement RouteFlashElement;
18605 
18606  for(unsigned int b = 0; b < SearchVector.size(); b++)
18607  {
18608  int H = GetFixedSearchElementAt(11, b).HLoc;
18609  int V = GetFixedSearchElementAt(12, b).VLoc;
18611  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
18612  RouteFlashElement.HLoc = H;
18613  RouteFlashElement.VLoc = V;
18615  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
18616  }
18617  Utilities->CallLogPop(348);
18618 }
18619 
18620 // ---------------------------------------------------------------------------
18621 
18622 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
18623 {
18624  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
18625  if(!PrefDirVector.empty())
18626  {
18627  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18628  {
18629  int H = PrefDirPtr->HLoc;
18630  int V = PrefDirPtr->VLoc;
18631  // check for any LCs that are closed to trains & set the flash values and store in the vector
18632  if(Track->IsLCAtHV(39, H, V))
18633  {
18634  if(Track->IsLCBarrierUpAtHV(0, H, V))
18635  {
18636  Track->LCChangeFlag = true;
18637  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
18638  CLC.HLoc = H;
18639  CLC.VLoc = V;
18641  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
18644  if(PrefDirRoute)
18645  {
18646  CLC.TypeOfRoute = 1;
18647  }
18648  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
18649  Track->ChangingLCVector.push_back(CLC);
18650  }
18651  }
18652  }
18653  }
18654  Utilities->CallLogPop(1948);
18655 }
18656 
18657 // ---------------------------------------------------------------------------
18658 
18660 /*
18661  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18662  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
18663  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18664  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18665 */
18666 {
18667  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
18668  if(!OverlayPlotted)
18669  {
18670  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18671  {
18672  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18673  {
18674  continue;
18675  }
18676  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
18677  Display->Update();
18678  }
18679  OverlayPlotted = true;
18680  }
18681  Utilities->CallLogPop(349);
18682 }
18683 
18684 // ---------------------------------------------------------------------------
18685 
18687 /*
18688  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18689  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
18690  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18691  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18692 */
18693 {
18694  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
18695  if(OverlayPlotted)
18696  {
18697  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18698  {
18699  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18700  {
18701  continue;
18702  }
18703  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
18704  Display->Update();
18705  }
18706  OverlayPlotted = false;
18707  }
18708  Utilities->CallLogPop(350);
18709 }
18710 
18711 // ---------------------------------------------------------------------------
18712 
18713 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
18714 {
18715 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
18716 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
18717 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
18718 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
18719 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
18720 messages, and allocate a repair time similar to points)
18721 */
18722 
18723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
18724  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
18725  {
18726  Utilities->CallLogPop(2528);
18727  return(false);
18728  }
18729  bool FirstSignalFound = false;
18730  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
18731  {
18732  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
18733 //check for a failed point where needs to change to make the route
18734 //shouldn't be any but check to be safe
18735  int Attr = TE.Attribute;
18736  if(PDVIt->TrackType == Points)
18737  {
18738  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
18739  {
18740  if(Attr == 1) //currently set to diverge
18741  {
18742  if(TE.Failed)
18743  {
18744  Utilities->CallLogPop(2529);
18745  return(false); //return without further checking
18746  }
18747  }
18748  }
18749  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
18750  {
18751  if(Attr == 0) //currently set to go straight
18752  {
18753  if(TE.Failed)
18754  {
18755  Utilities->CallLogPop(2530);
18756  return(false); //return without further checking
18757  }
18758  }
18759  }
18760  }
18761  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
18762  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
18763  //the search vector)
18764  int XLinkPosition = PDVIt->XLinkPos;
18765  if(PDVIt->XLinkPos == -1)
18766  {
18767  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
18768  {
18769  for(int x = 0; x < 4; x++)
18770  {
18771  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
18772  {
18773  XLinkPosition = x;
18774  break;
18775  }
18776  }
18777  }
18778  else
18779  {
18780  Utilities->CallLogPop(2549);
18781  return(false); //no point going any further
18782  }
18783  }
18784  if(XLinkPosition > -1) //should be by now but be safe
18785  {
18786  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18787  {
18788  FirstSignalFound = true; //the first signal doesn't change aspect
18789  continue;
18790  }
18791  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
18792  {
18793 /*
18794  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
18795  {
18796  continue; //ground signals don't fail
18797  }
18798 */
18799  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
18800  {
18802  IFE.TVPos = PDVIt->TrackVectorPosition;
18803  TE.Failed = true;
18804  TE.Attribute = 0; //stop aspect
18805  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
18806  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
18807  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
18808  " failed when changing aspect.\nTrains can only pass under signaller control.");
18809  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18810  //set repair time, random value in minutes between 10 and 179
18811  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18812  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18813  IFE.RepairTime = RepairTime;
18815  Track->FailedSignalsVector.push_back(IFE);
18817  int RouteNumber; //not used
18818  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
18819  { // 0 for LinkPos ok as a signal so only one track
18820  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
18821  }
18822  Utilities->CallLogPop(2535);
18823  return(true); //return so only allow one failure per route
18824  }
18825  }
18826  }
18827  }
18828  Utilities->CallLogPop(2531);
18829  return(false);
18830 }
18831 
18832 // ---------------------------------------------------------------------------
18833 // ---------------------------------------------------------------------------
18834 
18835 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
18836 {
18837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
18838  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18839  {
18840  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
18841  }
18842  Utilities->CallLogPop(120);
18843  return(AllRoutesVector.at(At));
18844 }
18845 
18846 // ---------------------------------------------------------------------------
18847 
18849 {
18850  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
18851  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18852  {
18853  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
18854  }
18855  Utilities->CallLogPop(121);
18856  return(AllRoutesVector.at(At));
18857 }
18858 
18859 // ---------------------------------------------------------------------------
18860 
18861 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
18862 /*
18863  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
18864 */
18865 {
18866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
18867  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18868  {
18869  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
18870  }
18871  Utilities->CallLogPop(351);
18872 }
18873 
18874 // ---------------------------------------------------------------------------
18875 
18876 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
18877 {
18878  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
18879  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18880  {
18881  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
18882  }
18883  Utilities->CallLogPop(1706);
18884 }
18885 
18886 // ---------------------------------------------------------------------------
18887 
18888 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
18889 /*
18890  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
18891  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
18892  Messages are given in TruncateRoute. If successful the route is truncated at and including
18893  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
18894  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
18895  length (train length).
18896 */
18897 {
18898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
18899  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
18900  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18901  {
18902  TTruncateReturnType ReturnFlag;
18903 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
18904  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
18905  if(ReturnFlag == NotInRoute)
18906  {
18907  continue;
18908  }
18909  else if(ReturnFlag == InRouteTrue)
18910  {
18911  Utilities->CallLogPop(352);
18912  return(true);
18913  }
18914  else if(ReturnFlag == InRouteFalse)
18915  {
18916  Utilities->CallLogPop(353);
18917  return(false);
18918  }
18919  }
18920  Utilities->CallLogPop(354);
18921  return(false);
18922 }
18923 
18924 // ---------------------------------------------------------------------------
18925 
18926 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
18927 /*
18928  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
18929  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
18930 */
18931 {
18932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
18933  AnsiString(LinkPos));
18934  if(TrackVectorPosition == -1) // allows for continuation entries & exits
18935  {
18936  Utilities->CallLogPop(355);
18937  return(false);
18938  }
18939  THVPair Route2MultiMapKeyPair;
18940 
18941  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
18942  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
18943  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18944  TRoute2MultiMapIterator Route2MultiMapIterator;
18945 
18946  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
18947  {
18948  Utilities->CallLogPop(356);
18949  return(false);
18950  }
18951  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
18952  {
18953  Utilities->CallLogPop(1422);
18954  return(true);
18955  }
18956  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
18957  {
18958  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18959 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18960 // realised after writing this that can't be points as would have been covered above, but leave anyway
18961  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
18962  Route2MultiMapIterator->second.second);
18963  EntryLinkPos = PrefDirElement1.ELinkPos;
18964  ExitLinkPos = PrefDirElement1.XLinkPos;
18965  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18966  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18967  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
18968  {
18969  Utilities->CallLogPop(357);
18970  return(true);
18971  }
18972  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
18973  {
18974  Utilities->CallLogPop(358);
18975  return(true);
18976  }
18977  }
18978  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
18979  {
18980  Utilities->CallLogPop(1423);
18981  return(true);
18982  }
18983  Utilities->CallLogPop(363);
18984  return(false); // none found
18985 }
18986 
18987 // ---------------------------------------------------------------------------
18988 
18989 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
18990  Graphics::TBitmap* &EntryDirectionGraphicPtr)
18991 /*
18992  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
18993  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
18994  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
18995  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
18996  for replotting of AutoSigsRoutes.
18997 */
18998 {
18999  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19000  AnsiString(LinkPos));
19001  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19002  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19003  if(TrackVectorPosition == -1)
19004  {
19005  Utilities->CallLogPop(364);
19006  return(NoRoute); // allows for continuation entries & exits
19007  }
19008  THVPair Route2MultiMapKeyPair;
19009 
19010  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
19011  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
19012  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19013  TRoute2MultiMapIterator Route2MultiMapIterator;
19014 
19015  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19016  {
19017  Utilities->CallLogPop(365);
19018  return(NoRoute); // none found
19019  }
19020  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19021  {
19022  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19023 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19024  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
19025  Route2MultiMapIterator->second.second);
19026  EntryLinkPos = PrefDirElement1.ELinkPos;
19027  ExitLinkPos = PrefDirElement1.XLinkPos;
19028  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19029  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19030  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
19031  {
19032  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19033  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
19034  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19035  {
19036  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19037  }
19038  if(PrefDirElement1.AutoSignals)
19039  {
19040  Utilities->CallLogPop(366);
19041  return(AutoSigsRoute);
19042  }
19043  else
19044  {
19045  Utilities->CallLogPop(367);
19046  return(NotAutoSigsRoute);
19047  }
19048  }
19049  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
19050  {
19051  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19052  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
19053  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19054  {
19055  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19056  }
19057  if(PrefDirElement1.AutoSignals)
19058  {
19059  Utilities->CallLogPop(368);
19060  return(AutoSigsRoute);
19061  }
19062  else
19063  {
19064  Utilities->CallLogPop(369);
19065  return(NotAutoSigsRoute);
19066  }
19067  }
19068  }
19069  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19070  {
19071  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19072  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19073 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19074  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
19075  EntryLinkPos = PrefDirElement2.ELinkPos;
19076  ExitLinkPos = PrefDirElement2.XLinkPos;
19077  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19078  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19079  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
19080  {
19081  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19082  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
19083  {
19084  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19085  }
19086  if(PrefDirElement2.AutoSignals)
19087  {
19088  Utilities->CallLogPop(370);
19089  return(AutoSigsRoute);
19090  }
19091  else
19092  {
19093  Utilities->CallLogPop(371);
19094  return(NotAutoSigsRoute);
19095  }
19096  }
19097  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
19098  {
19099  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19100  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
19101  {
19102  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19103  }
19104  if(PrefDirElement2.AutoSignals)
19105  {
19106  Utilities->CallLogPop(372);
19107  return(AutoSigsRoute);
19108  }
19109  else
19110  {
19111  Utilities->CallLogPop(373);
19112  return(NotAutoSigsRoute);
19113  }
19114  }
19115  ItPair.second--; // the second iterator points one past the last matching value
19116  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
19117  EntryLinkPos = PrefDirElement3.ELinkPos;
19118  ExitLinkPos = PrefDirElement3.XLinkPos;
19119  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19120  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19121  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
19122  {
19123  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19124  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
19125  {
19126  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19127  }
19128  if(PrefDirElement3.AutoSignals)
19129  {
19130  Utilities->CallLogPop(374);
19131  return(AutoSigsRoute);
19132  }
19133  else
19134  {
19135  Utilities->CallLogPop(375);
19136  return(NotAutoSigsRoute);
19137  }
19138  }
19139  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
19140  {
19141  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19142  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
19143  {
19144  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19145  }
19146  if(PrefDirElement3.AutoSignals)
19147  {
19148  Utilities->CallLogPop(376);
19149  return(AutoSigsRoute);
19150  }
19151  else
19152  {
19153  Utilities->CallLogPop(377);
19154  return(NotAutoSigsRoute);
19155  }
19156  }
19157  }
19158  Utilities->CallLogPop(378);
19159  return(NoRoute); // none found
19160 }
19161 
19162 // ---------------------------------------------------------------------------
19163 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
19164 /*
19165  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
19166  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
19167 */
19168 {
19169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
19170  AnsiString(LinkPos));
19171  if(TrackVectorPosition == -1)
19172  {
19173  RouteNumber = -1;
19174  Utilities->CallLogPop(379);
19175  return(NoRoute); // allows for continuation & buffer entries & exits
19176  }
19177  THVPair Route2MultiMapKeyPair;
19178 
19179  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
19180  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
19181  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19182  TRoute2MultiMapIterator Route2MultiMapIterator;
19183 
19184  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19185  {
19186  RouteNumber = -1;
19187  Utilities->CallLogPop(380);
19188  return(NoRoute); // none found
19189  }
19190  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19191  {
19192  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19193 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19194  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
19195  Route2MultiMapIterator->second.second);
19196  EntryLinkPos = PrefDirElement1.ELinkPos;
19197  ExitLinkPos = PrefDirElement1.XLinkPos;
19198  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19199  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19200  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
19201  {
19202  RouteNumber = Route2MultiMapIterator->second.first;
19203  if(PrefDirElement1.AutoSignals)
19204  {
19205  Utilities->CallLogPop(381);
19206  return(AutoSigsRoute);
19207  }
19208  else
19209  {
19210  Utilities->CallLogPop(382);
19211  return(NotAutoSigsRoute);
19212  }
19213  }
19214  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
19215  {
19216  RouteNumber = Route2MultiMapIterator->second.first;
19217  if(PrefDirElement1.AutoSignals)
19218  {
19219  Utilities->CallLogPop(383);
19220  return(AutoSigsRoute);
19221  }
19222  else
19223  {
19224  Utilities->CallLogPop(384);
19225  return(NotAutoSigsRoute);
19226  }
19227  }
19228  }
19229  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19230  {
19231  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19232  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19233 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19234  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
19235  EntryLinkPos = PrefDirElement2.ELinkPos;
19236  ExitLinkPos = PrefDirElement2.XLinkPos;
19237  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19238  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19239  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
19240  {
19241  RouteNumber = ItPair.first->second.first;
19242  if(PrefDirElement2.AutoSignals)
19243  {
19244  Utilities->CallLogPop(385);
19245  return(AutoSigsRoute);
19246  }
19247  else
19248  {
19249  Utilities->CallLogPop(386);
19250  return(NotAutoSigsRoute);
19251  }
19252  }
19253  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
19254  {
19255  RouteNumber = ItPair.first->second.first;
19256  if(PrefDirElement2.AutoSignals)
19257  {
19258  Utilities->CallLogPop(387);
19259  return(AutoSigsRoute);
19260  }
19261  else
19262  {
19263  Utilities->CallLogPop(388);
19264  return(NotAutoSigsRoute);
19265  }
19266  }
19267  ItPair.second--; // the second iterator points one past the last matching value
19268  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
19269  EntryLinkPos = PrefDirElement3.ELinkPos;
19270  ExitLinkPos = PrefDirElement3.XLinkPos;
19271  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19272  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19273  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
19274  {
19275  RouteNumber = ItPair.second->second.first;
19276  if(PrefDirElement3.AutoSignals)
19277  {
19278  Utilities->CallLogPop(389);
19279  return(AutoSigsRoute);
19280  }
19281  else
19282  {
19283  Utilities->CallLogPop(390);
19284  return(NotAutoSigsRoute);
19285  }
19286  }
19287  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
19288  {
19289  RouteNumber = ItPair.second->second.first;
19290  if(PrefDirElement3.AutoSignals)
19291  {
19292  Utilities->CallLogPop(391);
19293  return(AutoSigsRoute);
19294  }
19295  else
19296  {
19297  Utilities->CallLogPop(392);
19298  return(NotAutoSigsRoute);
19299  }
19300  }
19301  }
19302  RouteNumber = -1;
19303  Utilities->CallLogPop(393);
19304  return(NoRoute); // none found
19305 }
19306 
19307 // ---------------------------------------------------------------------------
19308 
19309 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
19310 /*
19311  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
19312  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
19313  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
19314  and Route2MultiMap.
19315 */
19316 {
19317  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
19318  TOneRoute EmptyRoute;
19319 
19320  EmptyRoute.RouteID = NextRouteID;
19321  NextRouteID++;
19322 
19323  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19324  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19325  {
19326  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
19327  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
19328  }
19329  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
19330  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
19331 
19332  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
19333  Utilities->CallLogPop(394);
19334 }
19335 
19336 // ---------------------------------------------------------------------------
19337 
19339 /*
19340  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
19341  that is already in Route is used.
19342 */
19343 {
19344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
19345  TOneRoute EmptyRoute;
19346 
19347  EmptyRoute.RouteID = Route->RouteID;
19348 
19349  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19350  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19351  {
19352  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
19353  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
19354  }
19355  Utilities->CallLogPop(1579);
19356 }
19357 
19358 // ---------------------------------------------------------------------------
19359 
19360 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
19361 /*
19362  When attaching a new route section to an existing route, it is sometimes necessary to erase the
19363  original route and create a new composite route. This function Erases all elements in the route
19364  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
19365  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
19366  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
19367  that are greater than the route number that is removed. The LockedRouteVector as also searched
19368  and if any relate to the route that has been cleared they are erased too, but the fact that one
19369  has been found is recorded so that it can be re-established later.
19370 */
19371 {
19372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
19373  THVPair Route2MultiMapKeyPair;
19374  TRoute2MultiMapEntry Route2MultiMapEntry;
19375  TRoute2MultiMapIterator Route2MultiMapIterator;
19376 
19377 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
19378 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
19379 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
19380 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
19381 // If so the locked route is removed from the locked vector and is lost.
19382  LockedRouteRearTrackVectorPosition = 0;
19383  LockedRouteLastTrackVectorPosition = 0;
19384  LockedRouteLastXLinkPos = 0;
19385  LockedRouteLockStartTime = TDateTime(0);
19386  if(!LockedRouteVector.empty())
19387  {
19388  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19389  {
19390  if(LRVIT->RouteNumber == RouteNumber)
19391  {
19392  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
19393  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
19394  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
19395  LockedRouteLockStartTime = LRVIT->LockStartTime;
19396  LockedRouteFoundDuringRouteBuilding = true;
19397  LockedRouteVector.erase(LRVIT);
19398  }
19399  }
19400  }
19401  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
19402  {
19403  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
19404  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
19405  }
19406  Utilities->CallLogPop(395);
19407 }
19408 
19409 // ---------------------------------------------------------------------------
19410 
19412  TRoute2MultiMapIterator &Route2MultiMapIterator)
19413 /*
19414  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
19415  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
19416  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
19417  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
19418  are given for failure.
19419 */
19420 {
19421  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19422  AnsiString(VLoc) + "," + AnsiString(ELink));
19423  TRouteElementPair ReturnPair;
19424 
19425  ReturnPair.first = -1;
19426  ReturnPair.second = 0;
19427  THVPair Route2MultiMapKeyPair;
19428 
19429  Route2MultiMapKeyPair.first = HLoc;
19430  Route2MultiMapKeyPair.second = VLoc;
19431  TRoute2MultiMapEntry Route2MultiMapEntry;
19432 
19433  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
19434  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19435 
19436  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19437  Route2MultiMapIterator = ItPair.first;
19438 
19439  if(ItPair.first == ItPair.second)
19440  {
19441  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
19442  }
19443  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
19444  {
19445  ReturnPair.first = ItPair.first->second.first;
19446  ReturnPair.second = ItPair.first->second.second;
19447  Route2MultiMapIterator = ItPair.first;
19448  Utilities->CallLogPop(396);
19449  return(ReturnPair);
19450  }
19451  ItPair.first++;
19452  if(ItPair.first == ItPair.second)
19453  {
19454  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
19455  }
19456  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
19457  {
19458  ReturnPair.first = ItPair.first->second.first;
19459  ReturnPair.second = ItPair.first->second.second;
19460  Route2MultiMapIterator = ItPair.first;
19461  Utilities->CallLogPop(397);
19462  return(ReturnPair);
19463  }
19464  Utilities->CallLogPop(398);
19465  return(ReturnPair);
19466 }
19467 
19468 // ---------------------------------------------------------------------------
19469 
19470 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
19471 /*
19472  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
19473  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
19474  RouteNumber (route position in AllRoutes vector is returned as a reference.
19475  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
19476  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
19477 */
19478 {
19479  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
19480  AnsiString(VLoc) + "," + AnsiString(ELink));
19481  THVPair Route2MultiMapKeyPair;
19482 
19483  Route2MultiMapKeyPair.first = HLoc;
19484  Route2MultiMapKeyPair.second = VLoc;
19485  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19486 
19487  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19488 
19489  if(ItPair.first == ItPair.second)
19490  {
19491  RouteNumber = -1;
19492  Utilities->CallLogPop(2032);
19493  return(false);
19494  }
19495  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
19496  {
19497  RouteNumber = ItPair.first->second.first;
19498  Utilities->CallLogPop(2033);
19499  return(true);
19500  }
19501  ItPair.first++;
19502 
19503  if(ItPair.first == ItPair.second)
19504  {
19505  RouteNumber = -1;
19506  Utilities->CallLogPop(2034);
19507  return(false);
19508  }
19509  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
19510  {
19511  RouteNumber = ItPair.first->second.first;
19512  Utilities->CallLogPop(2035);
19513  return(true);
19514  }
19515  RouteNumber = -1;
19516  Utilities->CallLogPop(2036);
19517  return(false);
19518 }
19519 
19520 // ---------------------------------------------------------------------------
19521 
19522 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
19523 /*
19524  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
19525  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
19526  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
19527  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
19528  Called by TAllRoutes::AddRouteElement.
19529 */
19530 {
19531  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19532  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
19533  THVPair Route2MultiMapKeyPair;
19534 
19535  Route2MultiMapKeyPair.first = HLoc;
19536  Route2MultiMapKeyPair.second = VLoc;
19537  TRoute2MultiMapEntry Route2MultiMapEntry;
19538 
19539  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
19540  TRouteElementPair RouteElementPair;
19541 
19542  RouteElementPair.first = RouteNumber;
19543  RouteElementPair.second = RouteElementNumber;
19544  Route2MultiMapEntry.second = RouteElementPair;
19545 
19546  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
19547  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
19548  {
19549  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
19550  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
19551  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
19552  {
19553  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
19554  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
19555  {
19556  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19557  }
19558  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
19559  }
19560  else
19561  // same ELink so have an error
19562  {
19563  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
19564  }
19565  }
19566  else
19567  {
19568  Route2MultiMap.insert(Route2MultiMapEntry);
19569  }
19570 // element at H&V not found in map so insert it
19571  Utilities->CallLogPop(399);
19572 }
19573 
19574 // ---------------------------------------------------------------------------
19575 
19577 /*
19578  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
19579  and the second in the reference SecondPair. If there's only one then it's the function return
19580 */
19581 {
19582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19583  AnsiString(VLoc));
19585 
19586  TempPair.first = -1;
19587  TempPair.second = 0;
19588  SecondPair = TempPair;
19589  TRoute2MultiMapIterator Route2MultiMapIterator;
19590  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
19591  THVPair Route2MultiMapKeyPair;
19592 
19593  Route2MultiMapKeyPair.first = HLoc;
19594  Route2MultiMapKeyPair.second = VLoc;
19595  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19596  {
19597  Utilities->CallLogPop(400);
19598  return(TempPair);
19599  }
19600  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19601  {
19602  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19603  Utilities->CallLogPop(401);
19604  return(Route2MultiMapIterator->second);
19605  }
19606  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19607  {
19608  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19609  TempPair = ItRange.first->second;
19610  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
19611  Utilities->CallLogPop(402);
19612  return(TempPair);
19613  }
19614  Utilities->CallLogPop(403);
19615  return(TempPair);
19616 }
19617 
19618 // ---------------------------------------------------------------------------
19619 
19620 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
19621 /*
19622  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
19623  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
19624 */
19625 {
19626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
19627  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
19628  {
19629  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
19630  {
19631  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
19632  TAllRoutes::TRouteElementPair SecondPair;
19633  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
19634  if(RouteElementPair.first == -1)
19635  // failed to find element in multimap
19636  {
19637  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
19638  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
19639  }
19640  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
19641  // neither pair has expected route number
19642  {
19643  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19644  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
19645  (AnsiString)Caller);
19646  }
19647  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
19648  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
19649  {
19650  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19651  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
19652  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
19653  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
19654  }
19655  }
19656  }
19657  unsigned int SizeVal = 0;
19658 
19659 // check map and sum of route sizes match
19660  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19661  {
19662  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
19663  }
19664  if(SizeVal != Route2MultiMap.size())
19665  {
19666  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
19667  (AnsiString)Caller);
19668  }
19669  Utilities->CallLogPop(404);
19670  return;
19671 }
19672 
19673 // ---------------------------------------------------------------------------
19674 
19675 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
19676 /*
19677  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
19678  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
19679  exceed that for the erased route. Where this is so the RouteNumber is decremented.
19680 */
19681 {
19682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
19683  if(!Route2MultiMap.empty())
19684  {
19685  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19686  {
19687  if(Route2MultiMapIterator->second.first > RouteNumber)
19688  {
19689  Route2MultiMapIterator->second.first--;
19690  }
19691  }
19692  }
19693  Utilities->CallLogPop(405);
19694 }
19695 
19696 // ---------------------------------------------------------------------------
19697 
19698 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
19699 /*
19700  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
19701  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
19702  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
19703 */
19704 {
19705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
19706  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
19707  if(!Route2MultiMap.empty())
19708  {
19709  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19710  {
19711  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
19712  {
19713  Route2MultiMapIterator->second.second--;
19714  }
19715  }
19716  }
19717  Utilities->CallLogPop(406);
19718 }
19719 
19720 // ---------------------------------------------------------------------------
19721 
19722 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
19723 /*
19724  Erases the route element from Route2MultiMap and from the PrefDirVector.
19725  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
19726  decremented if they are greater than the element number removed, and if the entire route is removed
19727  then the route numbers are also decremented in the map for route numbers that are greater than the route
19728  number that is removed.
19729 */
19730 {
19731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19732  AnsiString(ELink));
19733  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
19734  TRoute2MultiMapIterator Route2MultiMapIterator;
19735 
19736  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
19737  if(RequiredRoutePair.first == -1)
19738  {
19739  throw Exception("Failed to find route element in RemoveRouteElement");
19740  }
19741  Route2MultiMap.erase(Route2MultiMapIterator);
19742  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
19743 
19744 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
19745  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
19746 
19747  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
19748  {
19749  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
19750  }
19751 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
19752 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
19753 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
19754 // to check if a route element is present, and the element has already been removed from the map - see above.
19755 
19756 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
19757 /*
19758  int LockedVectorNumber = -1;
19759  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
19760  {
19761  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
19762  }
19763 */
19764 
19765 // erase element from route
19766  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
19767 // CheckMapAndRoutes();//test - drop - tested below
19768 
19769 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
19770 // be so as continuation exit is at the end of the route, and truncation is from the end
19772  {
19774  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19775  AutoSigVectorIT--)
19776  {
19777  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
19778  {
19779  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
19780  }
19781  }
19782  }
19783 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
19784 // and adjust all the corresponding route numbers
19785  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
19786  {
19787  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
19788  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
19789  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
19790 
19791 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
19792  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
19793  it is erased then - see TInterface::ApproachLocking
19794 
19795  if(LockedVectorNumber > -1)
19796  {
19797  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
19798  }
19799 */
19800  // decrement route numbers in the locked route vector whether or not this route is a locked route
19801  if(!LockedRouteVector.empty())
19802  {
19803  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19804  {
19805  if(LRVIT->RouteNumber > RequiredRoutePair.first)
19806  {
19807  LRVIT->RouteNumber--;
19808  }
19809  }
19810  }
19812  {
19814  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19815  AutoSigVectorIT--)
19816  {
19817  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
19818  {
19819  AutoSigVectorIT->RouteNumber--;
19820  }
19821  }
19822  }
19823  }
19824  CheckMapAndRoutes(7); // test
19825  Utilities->CallLogPop(407);
19826 }
19827 
19828 // ---------------------------------------------------------------------------
19829 
19830 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
19831 /*
19832  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
19833  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
19834  since that catches all route elements wherever created
19835 */
19836 {
19837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19838  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
19839  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
19840  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
19841  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
19842 } //number is one less than this
19843 
19844 // ---------------------------------------------------------------------------
19845 
19846 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
19847 /*
19848  Enter with signal at TrackVectorElement already set to red by the passing train.
19849  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
19850  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
19851  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
19852  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
19853  set signals in rear as it passed them.
19854 */
19855 {
19856  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
19857  "," + AnsiString(XLinkPos));
19858  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
19859  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
19860 
19861  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
19862  if(RouteElementPair.first == -1)
19863  {
19864  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
19865  }
19866  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
19867 
19868  RequiredPair = RouteElementPair;
19869  if(RouteElement.XLinkPos != XLinkPos)
19870  {
19871  if(SecondPair.first != -1)
19872  {
19873  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
19874  RequiredPair = SecondPair;
19875  if(RouteElement.XLinkPos != XLinkPos)
19876  {
19877  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
19878  }
19879  }
19880  else
19881  {
19882  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
19883  }
19884  }
19885 // new function
19886  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
19887  Utilities->CallLogPop(409);
19888 }
19889 
19890 // ---------------------------------------------------------------------------
19891 
19892 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
19893 /*
19894  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
19895  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
19896  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
19897  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
19898  changes from 0 to 1 to 2 for successive calls.
19899  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
19900  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
19901  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
19902  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
19903  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
19904 */
19905 {
19906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
19907  AnsiString(AccessNumber));
19908  TPrefDirElement RouteElement;
19909  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
19910 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
19911  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
19912 
19913  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
19914  {
19915  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
19916  }
19917  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
19918  {
19919  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
19920  }
19921  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
19922  x).XLinkPos] != End)
19923  {
19924  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
19925  }
19926 // new function
19927  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
19928  Utilities->CallLogPop(410);
19929 }
19930 
19931 // ---------------------------------------------------------------------------
19932 
19933 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
19934 /*
19935  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
19936  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
19937  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
19938  if autosigs the train will have set signals in rear as it passed them.
19939 
19940  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
19941  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
19942  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
19943  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
19944  then the function terminates.
19945 
19946  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
19947  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
19948  non-autosigs route, otherwise the signals won't be set behind the train.
19949 
19950  First the route is examined element by element from the RouteStartPosition towards the start of the
19951  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
19952  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
19953  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
19954  found behind the train.
19955 
19956  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
19957  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
19958  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
19959  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
19960  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
19961  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
19962  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
19963  or (c) truncating a route.
19964 
19965  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
19966  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
19967  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
19968  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
19969  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
19970  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
19971  the function returns true.
19972 
19973  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
19974  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
19975 */
19976 {
19977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
19978  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
19979  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
19980  int RearwardLinkedRouteNumber;
19981 
19982 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
19983  bool SkipForwardLook = false; //allow forward look in first call
19984  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
19985  //Attribute to 1+ final signal value in the route for use in further linked routes
19986  {
19987  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
19988  { //linked rearwards route)
19989  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19990  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
19991  {
19992  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
19993  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
19994  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
19995  {
19996  break;
19997  }
19998  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
19999  }
20000  }
20001  }
20002  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
20003  {
20004  int TrainID, TrainPosition, BehindTrainPosition;
20005  bool FoundTrain = false, BehindTrain = false;
20006  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
20007  {
20008  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
20009  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
20010  TrainID = TrackElement.TrainIDOnElement;
20011  if(TrackElement.TrackType == Bridge)
20012  {
20013  if(PrefDirElement.XLinkPos < 2)
20014  {
20015  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20016  }
20017  else
20018  {
20019  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20020  }
20021  }
20022  if(TrainID == -1)
20023  {
20024  continue;
20025  }
20026  else
20027  {
20028  FoundTrain = true;
20029  TrainPosition = x;
20030  break;
20031  }
20032  }
20033  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
20034  { //If there is a linked rear route then no need to deal with signals behind train here -
20035  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
20036  //set signals in rear as it passed them.
20037  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
20038  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
20039  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
20040  // need the element behind the rearmost train.
20041  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
20042  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
20043  TrainID = TrackElement.TrainIDOnElement;
20044  if(TrackElement.TrackType == Bridge)
20045  {
20046  if(PrefDirElement.XLinkPos < 2)
20047  {
20048  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20049  }
20050  else
20051  {
20052  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20053  }
20054  }
20055  if(TrainID != -1)
20056  {
20057  continue; // still on train
20058  }
20059  else
20060  {
20061  BehindTrain = true;
20062  BehindTrainPosition = x;
20063  break;
20064  }
20065  }
20066  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
20067  // so on for as many trains as there are on this (RouteNumber) route
20068  {
20069  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
20070  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
20071  } //for rearward signal setting
20072  }
20073  }
20074  Utilities->CallLogPop(411);
20075 }
20076 
20077 // ---------------------------------------------------------------------------
20078 
20079 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
20080 {
20081 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
20082 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
20083 rearmost linked route) - this because train cancels route elements that it touches)
20084 */
20085  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
20086  AnsiString(LookBackwardsFromHere));
20087  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
20088  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
20089  TPrefDirElement PrefDirElement, FirstElement;
20090  TTrackElement TrackElement;
20091  bool ExamineRoute = true;
20092 
20093  while(ExamineRoute)
20094  {
20095  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
20096  {
20097  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
20098  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
20099  TrainID = TrackElement.TrainIDOnElement;
20100  if(TrackElement.TrackType == Bridge)
20101  {
20102  if(PrefDirElement.XLinkPos < 2)
20103  {
20104  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20105  }
20106  else
20107  {
20108  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20109  }
20110  }
20111  if(TrainID > -1)
20112  {
20113  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
20114  {
20115  //any trains further back in route will be protected by the red signal behind the stopped train
20116  Utilities->CallLogPop(412);
20117  return(false);
20118  }
20119  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
20120  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
20121  //other way & can cancel the route
20122  {
20123  Utilities->CallLogPop(2203);
20124  return(false);
20125  }
20126  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
20127  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
20128  }
20129  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
20130  {
20131  if(TrackElement.Attribute == 0)
20132  {
20133  Utilities->CallLogPop(413);
20134  return(false); // OK, red signal in front of a train
20135  }
20136  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
20137  {
20138  SignalCount++;
20139  }
20140  if(SignalCount >= 3)
20141  {
20142  Utilities->CallLogPop(414);
20143  return(false);
20144  }
20145  }
20146  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
20147  // ElinkPos because working back along PrefDir to beginning
20148  {
20149  Utilities->CallLogPop(415);
20150  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
20151  }
20152  }
20153  //now look at linked rearwards routes
20154  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
20155  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
20156  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20157  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
20158  {
20159  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
20160  ExamineRoute = true;
20161  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
20162  }
20163  else
20164  {
20165  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
20166  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
20167  TrainID = PriorTrackElement.TrainIDOnElement;
20168  if(PriorTrackElement.TrackType == Bridge)
20169  {
20170  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
20171  {
20172  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20173  }
20174  else
20175  {
20176  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20177  }
20178  }
20179  if(TrainID > -1)
20180  {
20181  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
20182  {
20183  Utilities->CallLogPop(748);
20184  return(false);
20185  }
20186  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
20187  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
20188  //other way & can cancel the route
20189  {
20190  Utilities->CallLogPop(2204);
20191  return(false);
20192  }
20193  Utilities->CallLogPop(1962);
20194  return(true); //otherwise need to lock the route
20195  }
20196  ExamineRoute = false;
20197  }
20198  }
20199 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
20200 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
20201  Utilities->CallLogPop(416);
20202  return(false);
20203 }
20204 
20205 // ---------------------------------------------------------------------------
20206 
20207 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
20208  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
20209 {
20210  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
20211  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
20212  TPrefDirElement InternalPrefDirElement; // blank element
20213 
20214  PrefDirElement = InternalPrefDirElement;
20215  if(LockedRouteVector.empty())
20216  {
20217  Utilities->CallLogPop(417);
20218  return(false);
20219  }
20220 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
20221 // even if some elements have been removed from the front by a train
20222  bool InLockedRoute = false;
20223 
20224  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20225  {
20226  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
20227  {
20228  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
20229  // doesn't arise)
20230  InLockedRoute = true;
20231  break;
20232  }
20233  }
20234  if(!InLockedRoute)
20235  {
20236  Utilities->CallLogPop(418);
20237  return(false);
20238  }
20239  int RouteNumber, VectorCount = 0;
20240  TRouteType RouteType;
20241 
20242  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20243  {
20244  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
20245  if(RouteType == NoRoute)
20246  {
20247  continue;
20248  }
20249 /* can't use this test with front truncation
20250  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
20251  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
20252  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
20253  {
20254  throw Exception
20255  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
20256  }
20257 */
20258  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
20259  {
20260  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
20261  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
20262  {
20263  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20264  {
20265  PrefDirElement = InternalPrefDirElement;
20266  LockedVectorNumber = VectorCount;
20267  Utilities->CallLogPop(419);
20268  return(true);
20269  }
20270  }
20271  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
20272  {
20273  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20274  {
20275  PrefDirElement = InternalPrefDirElement;
20276  LockedVectorNumber = VectorCount;
20277  Utilities->CallLogPop(420);
20278  return(true);
20279  }
20280  else
20281  {
20282  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
20283  }
20284  }
20285  }
20286  VectorCount++;
20287  }
20288  Utilities->CallLogPop(421);
20289  return(false);
20290 }
20291 
20292 // ---------------------------------------------------------------------------
20293 
20295 {
20296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
20297  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20298  {
20299  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
20300  {
20301  Utilities->CallLogPop(963);
20302  return(x);
20303  }
20304  }
20305  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
20306 }
20307 
20308 // ---------------------------------------------------------------------------
20309 
20311 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
20312 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
20313 {
20314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20315  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20316  {
20317  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
20318  {
20319  Utilities->CallLogPop(2039);
20320  return(true);
20321  }
20322  }
20323  Utilities->CallLogPop(2040);
20324  return(false);
20325 }
20326 
20327 // ---------------------------------------------------------------------------
20328 
20330 {
20331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20332  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20333  {
20334  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
20335  {
20336  Utilities->CallLogPop(964);
20337  return(GetFixedRouteAt(159, x));
20338  }
20339  }
20340  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20341 }
20342 
20343 // ---------------------------------------------------------------------------
20344 
20346 {
20347  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
20348  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20349  {
20350  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
20351  {
20352  Utilities->CallLogPop(965);
20353  return(GetModifiableRouteAt(15, x));
20354  }
20355  }
20356  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20357 }
20358 
20359 // ---------------------------------------------------------------------------
20360 
20361 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
20362 {
20363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
20364  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
20365  Utilities->SaveFileInt(OutFile, NextRouteID);
20366  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20367  {
20368  TOneRoute OneRoute = GetFixedRouteAt(165, x);
20369  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
20370  OneRoute.SavePrefDirVector(6, OutFile);
20371  }
20372  Utilities->CallLogPop(1442);
20373 }
20374 
20375 // ---------------------------------------------------------------------------
20376 
20377 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
20378 {
20379  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
20380  int NumberOfRoutes;
20381 
20382  NumberOfRoutes = Utilities->LoadFileInt(InFile);
20383  NextRouteID = Utilities->LoadFileInt(InFile);
20384  for(int x = 0; x < NumberOfRoutes; x++)
20385  {
20386  TOneRoute OneRoute; // empty route
20387  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
20388  OneRoute.LoadPrefDir(2, InFile);
20390  {
20391  StoreOneRouteAfterSessionLoad(0, &OneRoute);
20392  }
20393  else
20394  {
20395  Utilities->CallLogPop(1443);
20396  return(false);
20397  }
20398  }
20399  Utilities->CallLogPop(1444);
20400  return(true);
20401 }
20402 
20403 // ---------------------------------------------------------------------------
20404 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
20405 {
20406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
20407  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
20408 
20409  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
20410  {
20411  Utilities->CallLogPop(1445);
20412  return(false);
20413  }
20414  int NextID = Utilities->LoadFileInt(InFile);
20415 
20416  if((NextID < 0) || (NextID > 1000000))
20417  {
20418  Utilities->CallLogPop(1446);
20419  return(false);
20420  }
20421  for(int x = 0; x < NumberOfRoutes; x++)
20422  {
20423  int RouteID = Utilities->LoadFileInt(InFile);
20424  if((RouteID < 0) || (RouteID > 20000))
20425  {
20426  Utilities->CallLogPop(1447);
20427  return(false);
20428  }
20429  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
20430  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
20431  {
20432  Utilities->CallLogPop(1448);
20433  return(false);
20434  }
20435  }
20436  Utilities->CallLogPop(1449);
20437  return(true);
20438 }
20439 
20440 // ---------------------------------------------------------------------------
20441 
20442 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
20443 {
20444  // return true for a loop
20445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
20446  AnsiString(StartPosition));
20447  if(EndPosition == StartPosition)
20448  {
20449  Utilities->CallLogPop(1839);
20450  return(true); // shouldn't happen but treat as a loop if does
20451  }
20452 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
20453  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
20454  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
20455 
20456  while(TrackIsInARoute(15, TVPos, LkPos))
20457  {
20458  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
20459  int NewLkPos = -1;
20460  if(NewTVPos > -1)
20461  {
20462  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
20463  if(NewLkPos == -1)
20464  {
20465  Utilities->CallLogPop(1840);
20466  return(true); // shouldn't arise but treat as loop if does
20467  }
20468  }
20469  else // reached a buffer or continuation
20470  {
20471  Utilities->CallLogPop(1841);
20472  return(false);
20473  }
20474 //Error found by Xeon notified by email 13/10/20.
20475 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
20476 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
20477 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
20478 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
20479 //New check added for v2.6.0
20480 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
20481 //as possible in case there are other unforeseen effects.
20482  int RouteNumber; //dummy, not used
20483  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
20484  {
20485  Utilities->CallLogPop(2241);
20486  return(false);
20487  }
20488  //now make the connected element the current element, read across the TV number and determine the exit link
20489  TVPos = NewTVPos;
20490  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
20491  {
20492  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
20493  {
20494  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
20495  {
20496  LkPos = 1;
20497  }
20498  else
20499  {
20500  LkPos = 3;
20501  }
20502  }
20503  else
20504  {
20505  LkPos = 0;
20506  }
20507  }
20508  else
20509  {
20510  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
20511  }
20512  if(TVPos == StartPosition)
20513  {
20514  Utilities->CallLogPop(1842);
20515  return(true); // it is a loop
20516  }
20517  }
20518  Utilities->CallLogPop(1843);
20519  return(false); // reached end of route so not a loop
20520 }
20521 
20522 // ---------------------------------------------------------------------------
20523 
20524 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20525 /*
20526  Track geometry allows diagonals to cross without occupying the same track element, so when
20527  route plotting it is necessary to check if there is an existing route or a train on such a crossing
20528  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
20529  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20530  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20531  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20532  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20533  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20534  Each of these is examined in turn for each route element in the relevant position.
20535 
20536  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
20537  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
20538  that returns false in all cases (including elements & links not present) except train present.
20539 */
20540 {
20541  int TrainID; // not used in this function
20542 
20543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
20544  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
20545  TPrefDirElement TempPrefDirElement;
20546  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20547 
20548  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
20549  if(FirstPair.first > -1)
20550  {
20551  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
20552  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20553  {
20554  Utilities->CallLogPop(310);
20555  return(true);
20556  }
20557  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20558  {
20559  Utilities->CallLogPop(311);
20560  return(true);
20561  }
20562  }
20563  if(SecondPair.first > -1)
20564  {
20565  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
20566  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20567  {
20568  Utilities->CallLogPop(312);
20569  return(true);
20570  }
20571  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20572  {
20573  Utilities->CallLogPop(313);
20574  return(true);
20575  }
20576  }
20577  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
20578  9, TrainID)))
20579  {
20580  Utilities->CallLogPop(1997);
20581  return(true);
20582  }
20583  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
20584  if(FirstPair.first > -1)
20585  {
20586  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
20587  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20588  {
20589  Utilities->CallLogPop(314);
20590  return(true);
20591  }
20592  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20593  {
20594  Utilities->CallLogPop(315);
20595  return(true);
20596  }
20597  }
20598  if(SecondPair.first > -1)
20599  {
20600  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
20601  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20602  {
20603  Utilities->CallLogPop(316);
20604  return(true);
20605  }
20606  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20607  {
20608  Utilities->CallLogPop(317);
20609  return(true);
20610  }
20611  }
20612  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
20613  9, TrainID)))
20614  {
20615  Utilities->CallLogPop(1998);
20616  return(true);
20617  }
20618  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
20619  if(FirstPair.first > -1)
20620  {
20621  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
20622  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20623  {
20624  Utilities->CallLogPop(318);
20625  return(true);
20626  }
20627  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20628  {
20629  Utilities->CallLogPop(319);
20630  return(true);
20631  }
20632  }
20633  if(SecondPair.first > -1)
20634  {
20635  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
20636  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20637  {
20638  Utilities->CallLogPop(320);
20639  return(true);
20640  }
20641  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20642  {
20643  Utilities->CallLogPop(321);
20644  return(true);
20645  }
20646  }
20647  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
20648  7, TrainID)))
20649  {
20650  Utilities->CallLogPop(1999);
20651  return(true);
20652  }
20653  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
20654  if(FirstPair.first > -1)
20655  {
20656  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
20657  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20658  {
20659  Utilities->CallLogPop(322);
20660  return(true);
20661  }
20662  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20663  {
20664  Utilities->CallLogPop(323);
20665  return(true);
20666  }
20667  }
20668  if(SecondPair.first > -1)
20669  {
20670  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
20671  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20672  {
20673  Utilities->CallLogPop(324);
20674  return(true);
20675  }
20676  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20677  {
20678  Utilities->CallLogPop(325);
20679  return(true);
20680  }
20681  }
20682  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
20683  3, TrainID)))
20684  {
20685  Utilities->CallLogPop(2000);
20686  return(true);
20687  }
20688  Utilities->CallLogPop(326);
20689  return(false);
20690 }
20691 
20692 // ---------------------------------------------------------------------------
20693 
20694 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20695 /*
20696  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
20697  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20698  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20699  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20700  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20701  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20702  Each of these is examined in turn for each route element in the relevant position.
20703 */
20704 {
20705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20706  "," + AnsiString(DiagonalLinkNumber));
20707  TPrefDirElement TempPrefDirElement;
20708  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20709 
20710  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
20711  if(FirstPair.first > -1)
20712  {
20713  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
20714  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20715  {
20716  Utilities->CallLogPop(2010);
20717  return(true);
20718  }
20719  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20720  {
20721  Utilities->CallLogPop(2011);
20722  return(true);
20723  }
20724  }
20725  if(SecondPair.first > -1)
20726  {
20727  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
20728  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20729  {
20730  Utilities->CallLogPop(2012);
20731  return(true);
20732  }
20733  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20734  {
20735  Utilities->CallLogPop(2013);
20736  return(true);
20737  }
20738  }
20739  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
20740  if(FirstPair.first > -1)
20741  {
20742  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
20743  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20744  {
20745  Utilities->CallLogPop(2014);
20746  return(true);
20747  }
20748  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20749  {
20750  Utilities->CallLogPop(2015);
20751  return(true);
20752  }
20753  }
20754  if(SecondPair.first > -1)
20755  {
20756  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
20757  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20758  {
20759  Utilities->CallLogPop(2016);
20760  return(true);
20761  }
20762  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20763  {
20764  Utilities->CallLogPop(2017);
20765  return(true);
20766  }
20767  }
20768  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
20769  if(FirstPair.first > -1)
20770  {
20771  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
20772  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20773  {
20774  Utilities->CallLogPop(2018);
20775  return(true);
20776  }
20777  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20778  {
20779  Utilities->CallLogPop(2019);
20780  return(true);
20781  }
20782  }
20783  if(SecondPair.first > -1)
20784  {
20785  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
20786  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20787  {
20788  Utilities->CallLogPop(2020);
20789  return(true);
20790  }
20791  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20792  {
20793  Utilities->CallLogPop(2021);
20794  return(true);
20795  }
20796  }
20797  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
20798  if(FirstPair.first > -1)
20799  {
20800  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
20801  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20802  {
20803  Utilities->CallLogPop(2022);
20804  return(true);
20805  }
20806  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20807  {
20808  Utilities->CallLogPop(2023);
20809  return(true);
20810  }
20811  }
20812  if(SecondPair.first > -1)
20813  {
20814  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
20815  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20816  {
20817  Utilities->CallLogPop(2024);
20818  return(true);
20819  }
20820  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20821  {
20822  Utilities->CallLogPop(2025);
20823  return(true);
20824  }
20825  }
20826  Utilities->CallLogPop(2026);
20827  return(false);
20828 }
20829 
20830 // ---------------------------------------------------------------------------
20831 
20832 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9433
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18926
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1321
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11706
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11679
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:438
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4779
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:572
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5653
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13224
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1737
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:813
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:19522
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10162
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:19933
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1375
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:805
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13748
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:823
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:436
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13264
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3843
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:803
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:286
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7408
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:18888
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:97
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1717
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:729
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5805
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7309
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5832
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1531
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:592
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1678
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1975
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10495
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:622
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:20694
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:438
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1708
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:70
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:613
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2871
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:557
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5985
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8336
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1541
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:651
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:19360
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:584
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13003
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7794
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10718
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9540
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14397
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:16958
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1141
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:19722
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:761
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1658
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12807
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4530
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3709
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1555
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8151
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:444
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4690
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1335
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6592
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10984
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3585
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1334
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:20207
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2904
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7780
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:227
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:20404
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:580
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9707
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1716
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1553
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1645
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:209
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:732
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:442
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:819
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3309
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16139
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8603
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13069
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:807
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:77
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2920
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:731
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1042
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:19470
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1402
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13320
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3906
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1781
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5945
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:303
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:744
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:381
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14268
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11720
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:576
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:632
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7809
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:89
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:19830
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7555
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:613
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:574
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10600
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1557
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1519
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:705
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:586
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:809
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1411
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6216
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1559
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:624
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8957
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:569
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10709
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1055
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:304
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:747
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:815
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3880
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:874
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:231
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9672
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1036
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:18876
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:508
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:17677
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1672
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1682
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7823
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:674
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7001
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:649
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:229
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8996
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:18861
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:827
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14037
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13774
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:927
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4615
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1925
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:436
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:787
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11187
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:19675
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4875
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1944
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:797
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:763
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:564
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1741
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:659
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11432
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:20310
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:592
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1053
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2888
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1565
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15272
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7436
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8793
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7515
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5856
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:696
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:318
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1545
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:687
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:18381
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1337
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:874
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13408
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12543
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1683
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1735
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:793
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13036
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:714
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:18507
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3686
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13727
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11475
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10850
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1827
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:939
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:583
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6039
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12856
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:827
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:628
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2943
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11732
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12051
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:433
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10744
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:119
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5904
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1861
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13975
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6116
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:893
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5696
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17924
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6573
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:95
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1366
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9468
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:713
TTrack::Up
@ Up
Definition: TrackUnit.h:613
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:829
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:587
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10723
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1513
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8760
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1676
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:759
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:205
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:18594
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1665
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6459
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:831
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8706
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7464
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10135
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:574
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:592
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:795
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19163
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1595
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12906
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11371
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4699
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:572
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10695
TGraphicElement::Width
int Width
Definition: TrackUnit.h:440
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:20079
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:20294
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:18989
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:801
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:800
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14806
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:661
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4188
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2406
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:694
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9608
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:12674
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:793
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:966
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5880
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:20377
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1557
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1547
TAllRoutes::RouteBackTruncateFlag
bool RouteBackTruncateFlag
used to flag the fact that a route is being truncated from the back in order to change the behaviour ...
Definition: TrackUnit.h:1722
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7162
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1066
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1068
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7995
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:18686
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:662
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7537
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5501
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:827
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13797
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:620
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11283
Parapet
@ Parapet
Definition: TrackUnit.h:67
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:18835
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:115
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:274
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9277
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:18659
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:827
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:19698
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:799
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1071
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:739
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:16551
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:207
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11503
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:12601
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1315
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:18622
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:550
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1374
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:874
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1405
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:19846
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:17577
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1715
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1652
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8305
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:205
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:19338
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:213
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3023
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9981
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6353
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2158
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:589
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:807
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2624
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:203
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1650
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7959
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12389
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13167
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:588
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1519
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10632
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8669
IDInt
Definition: TrackUnit.h:499
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2601
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:20345
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4503
TDisplay
Definition: DisplayUnit.h:49
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10382
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5246
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:872
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:442
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:20442
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1155
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9391
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:572
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7906
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1316
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13477
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:783
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:211
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14603
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1720
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7874
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:634
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:909
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1530
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1656
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1543
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1666
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4797
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9217
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:711
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15945
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1344
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:436
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13903
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1322
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13678
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:19411
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10066
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11354
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4210
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:18571
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9450
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1897
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:39
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:17467
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1062
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7753
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3786
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6136
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:13575
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9497
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12432
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:578
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:715
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:436
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:592
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1051
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:793
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3403
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:440
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1550
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:678
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:741
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1714
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:268
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:20524
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13372
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1040
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1521
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1044
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:789
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:903
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4758
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:19309
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1747
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8807
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:698
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:811
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:11141
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:709
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1376
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:18713
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:716
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:20361
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:582
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1907
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4741
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3763
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9729
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17280
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:11661
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12250
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8733
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:11633
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1049
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:19620
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:19576
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7235
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11012
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:735
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1403
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:17489
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5924
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:436
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:773
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10189
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:574
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:737
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:751
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:18848
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4907
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2799
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7834
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3165
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:17438
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:630
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14167
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:771
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:695
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1108
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11571
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1316
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:656
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:666
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11811
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:436
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1517
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:200
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8856
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:522
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1805
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9038
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:93
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:725
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13874
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:20329
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:612
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1373
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4435
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:817
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4632
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7697
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2002
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1057
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6499
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7492
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1405
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:213
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:668
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:781
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:707
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4657
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:791
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1660
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1064
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11603
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8256
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1329
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9646
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1038
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11248
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1812
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:105
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1519
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16366
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7680
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:821
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1521
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:617
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6516
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3663
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:585
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:757
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11174
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16782
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:682
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:626
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:689
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:825
RouteCall
@ RouteCall
Definition: TrackUnit.h:1322
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11745
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:91
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:672
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:19892
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:744
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11203
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10464
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:677
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:203
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6417
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15308
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:749
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11757
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1378
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1654
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1577
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:574
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10455
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1316
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17196
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:99
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11769
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4569
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11692
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852